Monday, 1 October 2007

Java 7 - Properties terminology

The debate around properties is hotting up. I'm going to try and contribute by defining a common terminology for everyone to communicate in.

Properties terminology

This is a classification of the three basic property types being debated. Names are given for each type of property. My hope is that the names will become widely used to allow everyone to explain their opinions more rapidly.

Note that although none of the examples show get/set methods, all of the options can support them. It should also be noted that the interface/class definitions are reduced and don't include all the possible methods.

Type 1 - Bean-independent property

(aka per-class, property-proxy, property adaptor)

This type of property consists of a type-safe wrapper for a named property on a specific type of bean. No reference is held to a bean instance, so the property is a lightweight singleton, exactly as per Field or Method. As such, it could be held as a static constant on the bean.

 public interface BeanIndependentProperty<B, V> {
   /**
    * Gets the value of the property from the specified bean.
    */
   V get(B bean);
   /**
    * Sets the value of the property on the specified bean.
    */
   void set(B bean, V newValue);
   /**
    * Gets the name of the property.
    */
   String propertyName();
 }

This type of property is useful for meta-level programming by frameworks. The get and set methods are not intended to be used day in day out by most application developers. Instead, the singleton bean-independent property instance is passed as a parameter to a framework which will store it for later use, typically against a list of actual beans.

A typical use case would be defining the properties on a bean to a comparator, for example comparing surnames, and if they are equal then forenames. Clearly, the comparator needs to be defined completely independently to any actual bean instance.

 Comparator<Person> comp = new MultiPropertyComparator<Person>(
   Person.SURNAME, Person.FORENAME   // bean-independent property defined as static constant
 );

Bean-independent properties can be implemented in two main ways. The first option uses reflection to access the field:

 public class Person {
  public static final BeanIndependentProperty<Person, String> SURNAME =
      ReflectionIndependentProperty.create(Person.class, "surname");
  private String surname;
 }

The second option uses an inner class to access the field:

 public class Person {
  public static final BeanIndependentProperty<Person, String> SURNAME =
      new AbstractIndependentProperty("surname") {
        public String get(Person person) { return person.surname; }
        public void set(Person person, String newValue) { person.surname = newValue; }
      };
  private String surname;
 }

As bean-independent properties are static singletons, they should be stateless and immutable.

Type 2 - Bean-attached property

(aka per-instance)

This type of property consists of a type-safe wrapper for a named property on a specific instance of a bean. As the bean-attached property is connected to a bean, it must be accessed via an instance method.

 public interface BeanAttachedProperty<B, V> {
   /**
    * Gets the value of the property from the stored bean.
    */
   V get();
   /**
    * Sets the value of the property on the stored bean.
    */
   void set(V newValue);
   /**
    * Gets the name of the property.
    */
   String propertyName();
 }

This type of property is useful for frameworks that need to tie a property on a specific bean to a piece of internal logic. The most common example of this is many parts of the Beans Binding JSR, such as textfield bindings.

The get and set methods are not intended to be used day in day out by most application developers. Instead, the bean-attached property instance is passed as a parameter to a framework which will store it for later use.

A typical use case would be defining the binding from a person's surname to a textfield. In this scenario we are binding the surname on a specific bean to the textfield on a specific form.

 bind( myPerson.surnameProperty(), myTextField.textProperty() );

Bean-attached properties can be implemented in two main ways. The first option uses reflection to access the field. This example show the attached property being created new each time (on-demand), however it could also be cached or created when the bean is created:

 public class Person {
  public BeanAttachedProperty<Person, String> surnameProperty() {
    return ReflectionAttachedProperty.create(this, "surname");
  }
  private String surname;
 }

The second option uses an inner class to access the field. Again, this example show the attached property being created new each time (on-demand), however it could also be cached or created when the bean is created:

 public class Person {
  public BeanAttachedProperty<Person, String> surnameProperty() {
    return new AbstractAttachedProperty("surname") {
        public String get() { return surname; }
        public void set(String newValue) { surname = newValue; }
      };
  private String surname;
 }

Bean-attached properties are merely pointers to the data on the bean. As such, they should be stateless and immutable.

Type 3 - Stateful property

(aka bean-properties, property objects, Beans 2.0, Eclipse IObservableValue)

Note that stateful properties have been implemented in the bean-properties project, however that project goes well beyond the description below.

This type of property consists of a stateful property on a specific instance of a bean. The property is a fully fledged object, linked to a specific bean, that holds the entire state of the property, including it's value. This approach is based around an alternative to the standard beans specification, however get/set methods can be added if desired.

 public class StatefulProperty<B, V> {
   private B bean;
   private V value;
   /**
    * Constructor initialising the value.
    */
   StatefulProperty<B, V>(B bean, V initialValue) {
     this.bean = bean;
     value = initialValue;
   }
   /**
    * Gets the value of the property from the stored bean.
    */
   public V get() { return value }
   /**
    * Sets the value of the property on the stored bean.
    */
   public void set(V newValue) { value = newValue; }
   /**
    * Gets the name of the property.
    */
   public String propertyName();
 }

This type of property is intended for application developers to use day in day out. However it is not intended to be used in the same way as normal get/set methods. Instead, developers are expected to code a bean and use it as follows:

 // bean implementation
 public class Person {
  public final StatefulProperty<Person, String> surname =
      new StatefulProperty<Person, String>(this, "surname");
  }
 }
 // usage (instead of get/set)
 String s = myPerson.surname.get();
 myPerson.surname.set("Colebourne");

The important point to note is that the surname field on the bean is final and a reference to the stateful property. The actual state of the property is within the stateful property, not directly within the bean.

A stateful property fulfils the same basic API as a bean-attached property (type 2). As such in can be used in the same use cases. However, because a stateful property is an object in its own right, it can have additional state and metadata added as required.

The key difference between bean-attached (type 2) and stateful (type 3) is the location of the bean's state. This impacts further in that bean-attached properties are intended primarily for interaction with frameworks, whereas stateful properties are intended for everyday use.

Language syntax changes

Both bean-independent (type 1) and bean-attached (type 2) properties benefit from language syntax change. This would be used to access the property (not the value) to pass to the framework in a compile-safe, type-safe, refactorable way:

 // bean-independent - accessed via the classname
 BeanIndependentProperty<Person, String> property = Person#surname;
 
 // bean-attached - accessed via the instance
 BeanAttachedProperty<Person, String> property = myPerson#surname;

Stateful properties (type 3) do not need a language change to access the property as they are designed around it, making it directly available and fully safe.

The second area of language change is definition of properties. This is a complicated area, which I won't cover here, where all three types of property would benefit from language change.

The third area of language change is access to the value of a property. Again, there are many possible syntaxes and implications which I won't cover here.

Combination

The full benefit of bean-independent (type 1) and bean attached (type 2) properties occurs when they are combined. Additional methods can be added to each interface to aid the integration, and any language syntax change becomes much more powerful.

Summary

I hope that these definitions will prove useful, and provide a common terminology for the discussion of properties in Java.

Opinions are welcome, and I will make tweaks if necessary!

7 comments:

  1. Thanks Stephen, this is helpful.

    ReplyDelete
  2. Great,
    your classification clearly outperform mime :)

    Just some clarifications, currently Beans Binding JSR uses type 1 even if type 2 seems more suitable.

    There is a third way to implement type 1 and 2
    using sun.misc.Unsafe.

    You don't talk about serialization ?

    cheers,
    Rémi

    ReplyDelete
  3. Stephen Colebourne2 October 2007 00:30

    Some parts of Beans Binding (Table columns) need type 1. Most other parts would be better with type 2. Thats why I think a combination of type 1 and 2 would be best. (I'm working on the principle that type 3 may be too radical for Sun, although it would be nice to be proved wrong).

    I haven't thought much about serialization, so I didn't mention it. Plus its a long entry anyway :-)

    ReplyDelete
  4. FWIW, the Eclipse binding framework uses type 3 and calls it IObservableValue; the concrete implementation of that interface is called WritableValue but there are others (like, for example, ComputedValue). Analogously, you can find IObservableList, IObservableSet, and IObservableMap.

    ReplyDelete
  5. Stephen, in the "Type 3 - Stateful property" you mentioned that this is essentially bean properties but the code you presented is quite a bit over simplified without explaining the notions of container, injected context objects etc... without which bean-properties is meaningless.
    I think its best either to clarify that your example is not of a bean-property from the given URL or possibly link to the actual code?
    It is BSD so no tainting etc... would occur for your readers ;-)

    Notice the base property has no getters/setters:
    https://bean-properties.dev.java.net/source/browse/bean-properties/src/net/java/dev/properties/BaseProperty.java?rev=1.4&view=markup

    Here is the RW property:
    https://bean-properties.dev.java.net/source/browse/bean-properties/src/net/java/dev/properties/Property.java?rev=1.1&view=markup

    https://bean-properties.dev.java.net/source/browse/bean-properties/src/net/java/dev/properties/

    Maybe the JavaDoc would be more intuitive:
    https://bean-properties.dev.java.net/javadoc/overview-summary.html

    ReplyDelete
  6. Am I the only one who misses Delphi? That language had property support in spades. The event support was pretty good too, although not as good as C# delegates.

    I can't understand for the life of me how Java could have dropped the ball on properties. Delphi already had property semantics worked down to a science before Java came along. Were Sun not paying attention, or did they just think that redundant getter/setter methods were a *good* thing?

    The Javabeans specification has never been enough to make up for it. The fact that's it's just a meta-design principle that the compiler doesn't enforce or endorse has not helped matters. Personally I would love to see properties become first-class citizens in Java, but I despair that doing so this late in the game will be as useful as adding object orientation was to PHP. I hope I'm wrong.

    I've used a variant of type 3 in my own code:

    class Reference { // not to be confused with java.lang.ref.Reference
    __T value;
    __public Reference(T initialValue) { set(initialValue); }
    __public void set(T value) { this.value = value; }
    __public T get() { return value; }
    }

    It's just a generified object holder, and has no concept of a managing container as in your StatefulProperty example. However I've found it useful in two situations: getting around local variables having to be final to be accessible in an inner class, and enabling pseudo pass-by-reference semantics.

    I'm curious why the StatefulProperty would have a reference to the container bean? I'm guessing you stripped out some cruft from your examples to keep things simple but from what's left I can't tell what useful purpose it would serve.

    ReplyDelete
  7. Stephen Colebourne2 October 2007 22:28

    @Boris, Thanks for the Eclipse link which is now in the article.

    @Shai, I clarified the type 3 description to emphasise that it isn't bean-properties (although I still haven't groked your container and context concepts.

    @Matthew, Yes, the JavaBean spec is a pathetic hack of a design, but its there now and we can't do much about it. (Properties weren't in the original language because it was designed for set-top boxes and such like).

    As for why the stateful property needs to link to the bean, well I guess it actually doesn't. I've not done the detailed design, so consider it a 'gut feeling' that it would be better if it did.

    ReplyDelete