Sunday 29 May 2011

Beans and properties

A few words on beans and properties in Java, prompted by the JavaFX 2.0 API and my work on Joda-Beans.

Beans and Properties

I was prompted to write this by the new API of JavaFX 2.0. It has a new extension to JavaBeans that adds support for properties, so that the JavaFX GUI can bind one property to another. I've been writing property extensions to JavaBeans for over 12 years now, so I feel I should comment on the design.

The basic design approach is to have an object representing each property on a bean. This object allows meta-data attributes to be stored per property (useful for marking errors), property change listeners (for GUIs) and tool access without reflection (allowing XML input/output, XPath, JSON etc).

The basic design adds an additional method to the JavaBean pattern. Alongside getSurname() and setSurname() there would be the property method surname(). This would return a Property object, which supports querying and setting the value, checking whether it was read-only or read-write, finding its type and adding property change listeners.

// basic querying via JavaBeans or property
  String surname = person.getSurname();
  String surname = person.surname().get();
  
  // additional features available with properties
  Property<String> property1 = person.surname();
  Property<String> property2 = person.property("surname");
  Map<String, Property<?>> propertyMap = person.propertyMap();
  person.surname().setAttribute("error", "MANDATORY");
  person.surname().addListener(...);

All the versions of this I've written follow a pattern relatively similar to that above. And the JavaFX 2.0 design is remarkably similar to this. However, some implementations of the pattern are more successful than others.

Version 1 - Original Joda

My initial work in the area was private, but I wrote a variation in open source around 2000 (unmaintained from 2002). This was the first Joda project (before Joda-Time), and still lives on the web here (Javadoc). Here is the original Joda approach (shown with generics for clarity):

public interface Person {
    Property<String> surname();
    String getSurname();
    void setSurname(String surname);
  }

In that project, the class was created using a Proxy object. Clearly, this approach was rather limiting, as a factory had to be used to created an instance of a bean. For various reasons, including the factories, this version was abandoned.

Version 2 - Instantiated Property objects

This version existed at one of my old day jobs. It used code generation rather than Proxy, which was better. However, it used this approach to the beans:

public class Person extends Bean {
    private final Property<String> surname = new Property(String.class);  // object created when person created
 
    public Property<String> surname() { return surname; }
    public String getSurname() { return (Strung) surname.get(); }     // state held on the property
    public void setSurname(String surname) { surname.set(surname); }
  }

Note that every time a Person is created, a Property object is created. Now imagine what happens when you have 20 properties on the bean - thats 21 object creations for an empty Person! And 21 garbage collections! It turns out that this design works OK for client side work, where there is a single machine and processing is limited by what one human can do. However, on the server side it performs horribly. Thus, it got converted into version 3.

Version 3 - Data on the bean

The version 2 approach stored all the state on the Property, but this approach does not work well with the JVM (it could, if the JVM/Java had the ability to inline the state of immediate child objects into the state of the parent object). Thus, the next approach was to move all the state from the property to the bean:

public class Bean {
    private final Map<String, String> attributes;
  }
  public class Person extends Bean {
    private final String surname;
 
    // code generated:
    public Property surname() { return new Property<String>(this, "surname"); }
    public String getSurname() { return surname; }
    public void setSurname(String surname) { this.surname = surname; }
 
    protected Object propertyGet(String propertyName) {
      switch (propertyName.hashCode()) {
        case 36527358: return getSurname();  // number is "surname".hashCode()
      }
      return null;
    }
  }

This approach moves all the state from the property back to the bean itself. The superclass would store any common items, like the attribute map (for error code) or the listeners, while the main person class stores the data using normal fields. The code generation adds a method that connects up the field without reflection.

Since the property is esentially stateless, it can be created on demand, used and then discarded. Short lived objects like that are good for the garbage collector, so long as they are not used too frequently. This design was successful on the server side, and supported all the other goodies, like conversion to and from XML and XPath searching, all without reflection. I believe that a dynamic code generation approach would also work, but the static code generation was effective enough that we didn't go further.

Version 4 - Joda-Beans (the next generation...)

The new Joda-Beans project (Javadoc) is an open source version of the version 3 approach, written from the ground up, but focussed on the essential elements for simplicity. It is currently in use at OpenGamma.

Again, a code generator is used to create the getters, setters and property methods, plus the supporting methods like propertyGet() and propertySet(). This time however, there is a greater focus on the meta-property level, which is the representation of the surname property as a concept, rather than tied to a particular bean instance. Think of the relationship between a property and a meta-property as similar to the relationship between an object and a class. (Effectively, Joda-beans defines both type 1 and type 2 properties.)

Rather than show a code sample here, I encourage you to look at some example classes to see what the code generator produces: Person, Address and the subclass CompanyAddress. The developer only writes the part outside the "code generated" block. The block is generated and re-generated without destroying any additional methods that are hand-written, so you can treat it as a "normal" class in all other ways.

Once again, the property objects hold no long-lived state and are created on demand. After 12 years of working with properties, I'm convinced that is the only design that scales acceptably for the server side on the JVM.

While the Joda-Beans project is not at v1.0 yet, it does work and enhances coding in Java. I'd love to have some early adopters try it out!

JavaFX 2.0

The JavaFX 2.0 approach uses stateful properties (Javadoc - javafx.beans packages). As I've discussed above, such an approach is powerful and conceptually simple, but has performance issues on anything other than the client side. Some articles on the JavaFX 2.0 approach are here and here Clearly, a major concern of the design is listeners, but I still have concerns about this approach.

Other implementations

There are other projects too that have tackled this problem, including Proper properties, Bean-properties, Better beans binding, and Remi's compiler changes (I'll add anything in the comments to this list). No project has won a large mind share though, and most seem unmaintained. A related solution is the ugly JPA typesafe extension.

Language solutions

I've said this before and I'll say it again. The lack of properties in Java is the biggest missing langauge feature and the amount of wasted development time globally by developers writing beans or tools to access properties is gigantic. Moreover, I believe that adding properties to Java is more important than both generics and closures, and should have been prioritised accordingly. (Every enterprise developer knows how much they use the broken JavaBean approach.)

The new JVM languages all have properties (no surprise there), although not all have proper support for obtaining an object to represent the property. Maybe one day, Java itself will support properties as a language feature, it is being vaguely mentioned now, but I'm not holding my breath.

Summary

Properties are a hugely beneficial language feature and raise the abstraction level of coding. While the Java language continues to not have them, you can use or help the Joda-Beans project to add them to your codebase.

My experience suggests that the JVM is poor at handling stateful property objects. Unfortunately, this is the route that JavaFX 2.0 has chosen. It might work for them (because they are client side, and because JVMs are getting faster), but I would advise against using JavaFX 2.0 properties on the server side without lots of performance testing.

Feedback welcome...