Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/stephenh/bindgen

data binding framework
https://github.com/stephenh/bindgen

Last synced: 16 days ago
JSON representation

data binding framework

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 Fred

None 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)