Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stephenh/bindgen
data binding framework
https://github.com/stephenh/bindgen
Last synced: 16 days ago
JSON representation
data binding framework
- Host: GitHub
- URL: https://github.com/stephenh/bindgen
- Owner: stephenh
- License: other
- Created: 2008-12-28T22:18:23.000Z (almost 16 years ago)
- Default Branch: master
- Last Pushed: 2020-10-13T09:19:06.000Z (about 4 years ago)
- Last Synced: 2024-10-12T10:15:30.899Z (about 1 month ago)
- Language: Java
- Homepage:
- Size: 5.86 MB
- Stars: 12
- Watchers: 4
- Forks: 7
- Open Issues: 3
-
Metadata Files:
- Readme: README.markdown
- License: LICENSE.markdown
Awesome Lists containing this project
README
Status
======I'm no longer actively maintaining this project; see [this fork](https://github.com/igloo-project/bindgen/) for a more active project.
Intro
=====A data binding framework that generates type-safe binding classes.
Or, OGNL with no strings.
Originally built for the [joist](http://joist.ws) web framework. See joist's [bindgen](http://joist.ws/bindgen.html) page for more docs.
A test case:
public void testEmployerThroughEmployee() {
Employer er = new Employer();
er.name = "at&t";Employee ee = new Employee();
ee.name = "bob";
ee.employer = er;EmployeeBinding eb = new EmployeeBinding(ee); // EmployeeBinding is generated by bindgen
eb.name(); // name() returns a StringBinding instance instead of the actual name String// During rendering TextBox calls StringBinding.get()
Assert.assertEquals("bob", new TextBox(eb.name()).toString());
Assert.assertEquals("at&t", new TextBox(eb.employer().name()).toString());// During POST procesing TextBox calls StringBinding.set()
new TextBox(eb.name()).set("newBob");
new TextBox(eb.employer().name()).set("newAt&t");
Assert.assertEquals("newBob", ee.name);
Assert.assertEquals("newAt&t", er.name);
}The point being that `eb.employer().name()` does not immediately return the value of `name`, but instead returns a `StringBinding` that the web framework can bind values into/out of as it serves the request.
Annotations
===========Bindgen is implemented as JDK6 annotation processor. When configured in your IDE (e.g. with project-specific settings in Eclipse), as soon as you add a `@Bindable` annotation to a class `Foo`, and hit save, the IDE immediately invokes the [Processor][2] behind the scenes and `FooBinding` is created.
[2]: /stephenh/bindgen/blob/master/processor/src/main/java/org/bindgen/processor/Processor.java
Another Example
===============This is a spike from a [Click][1]-like web framework I'm hacking around on:
@Bindable
public class HomePage extends AbstractPage {public Form form = new Form("Login");
public String username = "blah";
public String password;@Override
public void onInit() {
HomePageBinding b = bind(this); // static import of BindKeyword.bind
this.form.add(new TextField(b.username()));
this.form.add(new TextField(b.password()));
this.form.add(new SubmitField(b.submit()));
}public void submit() {
// do stuff with this.username and this.password
}
}The `HomePageBinding` class is auto-generated because of the `@Bindable` annotation on the `HomePage` class.
When the form POSTs, the TextFields call the `Binding.set` methods with their form values, which populates the `this.username` and `this.password` fields.
Fun things like type conversion using `Binding.getType()` method to go from strings -> whatever would be possible too.
[1]: http://click.sf.net
Stateless Bindings
==================Stateless bindings allows a single `Binding` instance to be evaluated against multiple roots in a thread-safe manner.
For example:
// Make just once instance of PersonBinding/StringBindingPath
PersonBinding p = new PersonBinding();
// Get a binding to their first name, through the Demographics object
StringBindingPath b = p.demographics().firstName();
// thread1
b.getWithRoot(bob); // returns Bob
b.setWithRoob(bob, "Bobby"); // changes bob
// thread2
b.getWithRoot(fred); // returns FredNone of the `getWithRoot`/`setWithRoot` invocations will step on each other's toes if running concurrently.
For more examples, see [MethodExampleStatelessTest][4].
[4]: /stephenh/bindgen/blob/master/examples/src/test/java/org/bindgen/example/methods/MethodExampleStatelessTest.java
Gotchas
=======* Eclipse: 3.5 works best--3.4 has several bugs that were fixed (see [263985][3])
* Eclipse: Annotating packages does not work
* Eclipse: Must be run *on* a JDK6 JVM--for Macs, this means 3.5 64-bit on the Apple 64-bit JDK6
* IntelliJ: Has mediocre support for annotation processors (last I checked)
* `javac`: Does not properly re-use already-generated classes, so pass `-AskipExistingBindingCheck=true` to re-generate all of the binding classes each time[3]: https://bugs.eclipse.org/bugs/show_bug.cgi?id=263985
Todo
====* Support extension methods, e.g. StringBinding could have extra methods like `length()`, `substring()`, etc., ideally configurable - done.
* Optional null-safe get/set, e.g. `eb.employer().name()` with a null `employer` could have `get()` return `null` and not NPE and `set()` could create a `new Employer()` to then call `setName()` on to again avoid the NPE
* Document options, `fixRawTypes`, `bindgen.log`, etc.
* Package a `bindgen-profiled` that has post-processed/something basic wall clock timing for performance analysis
* Make `Util.resolveTypeVarIfPossible` go away in favor of `Types.memberOf` (if possible)
* Looks like not--`Types.getMemberOf` doesn't resolve the generic in `setFoo(T foo)` when inherited by a `Child extends Parent`
* Probably needs the type `Parent` passed to it, which would mean remembering which super-type we're on instead of using `getAllMembers`
* Perhaps this would be solved by having child bindings inherit from the parent, e.g. `ChildBindingPath extends ParentBindingPath`
* Move most `Binding` methods behind a `asBound` method so that generated bindings don't have a polluted name space
* Add `Binding.getTag/setTag` for attaching metadata to binding instances (like gwt-mpv properties)