Monday, 8 January 2007

Java 7 - Property objects

Property syntax for Java 7 is the current discussion de jour. But I've been pointing out that we can go beyond get/set methods to create refactorable, compile checked property objects too.

Property syntax

The proposals being discussed revolve around syntax sugar code generation. So, the developer codes:

  public class Person {
    public property private String forename;
    public property private String surname;
  }

This would code generate the get/set methods:

  public class Person {
    private String forename;
    public String getForename() {return forename;}
    public void setForename(String forename) {this.forename = forename;}

    private String surname;
    public String getSurname() {return forename;}
    public void setSurname(String forename) {this.forename = forename;}
  }

Discussions on Javalobby and various blogs have focussed on the basic mechanics of the syntax for defining a property (keyword vs annotation vs token) and javadoc. In addition, a completely separate discussion about arrow operators has confused the debate. This is all fine, but in my view it misses the huge opportunity that is presented by this change.

Property objects

Currently, many many tools, especially frameworks, have to access beans in a dynamic way. By this I mean where a String property name is used to identify a property and reflection is used to access it. For example, this code might be used to bind the surname property in a validation, swing or database framework.

  binder.bind(person, "surname");

But this design is really utter madness!!! A key strength of Java is static typing, allowing compile time detection of errors and refactoring. With a design like this, all these features of Java are lost. For example, if you rename the property, then the binding will fail at runtime - yuck!!! What I want to write is:

  binder.bind( person.propertySurname() );

This is fully type-safe, refactorable and compiled. And once you have it, you find an awful lot of places where it can be used - Database bindings, Swing bindings, WebApp bindings, XML access, ...

Implementation

Full details can be foud in the download zip. In summary, there are four interfaces, the most significant is Property:

  public interface Property<B, T> {
    B bean();
    MetaProperty<B, T> metaProperty();
    T get();
    void set(T value);
  }

The bean method returns the bean that owns this property. The meta property holds details about the property such as its name and type. The get and set methods access the bean. The key point is that the get method actually calls the real getSurname() method on the bean. Likewise for set. So, the property object isn't breaking encapsulation, it just provides a higher level view of the property.

So, why the link to the current property debate? Well, the method propertySurname() needs to be generated along with the get and set methods. (In fact a metaProperty static method should be generated as well to complete the picture, see the download zip for full details). Anyway, with my proposal, the property code generation would create the following:

  public class Person {
    private String forename;
    public String getForename() {return forename;}
    public void setForename(String forename) {this.forename = forename;}
    public Property propertyForename() {return new SimpleProperty(this, "forename");}

    private String surname;
    public String getSurname() {return forename;}
    public void setSurname(String forename) {this.forename = forename;}
    public Property propertySurname() {return new SimpleProperty(this, "surname");}
  }

In other words, the proposal simply means one more syntax sugar generated method per property (see the download zip for full details).

Summary

The get/set method convention is extremely widely used in Java, and so any property solution must generate get and set methods. But if we go a little further and create property objects then we can dramatically change the interaction between our applications and the frameworks we use day-in day-out. Personally, I just love the refactorable, static-type checks and compiler safety that this brings. Do you agree?

20 comments:

  1. propertySurname wouldn't exist for old code without recompiling (not always practical). I disagree that it needs to exist at all, though.

    binding.bind(property object.surname);

    is unambiguous, and can be inferred from existing getSurname and setSurname methods.

    In short, any property proposal that treats old bytecode as a 2nd-class citizen needs improving.

    ReplyDelete
  2. Kieron Wilkinson8 January 2007 at 10:14

    Nice, I like it! I can see this would seriously clean up some of my code.

    Ricky: I don't think that really has to be a barrier to entry on this. If you have old beans which you cannot / do not want to recompile, you simply do not have the above features available.

    Just like Generics - if you are using old non-generic code where definitions of generics might be helpful, then your just as stuck. (okay, okay, that wouldn't be a simple recompile, but that's not my point).

    ReplyDelete
  3. If properties are added to the language and this feature is not possible I would call it syntax sugar. But being able to do "binder.bind( person.propertySurname() );" is just very necessary. A college and I made a comment on these features on the javapolis white boards (topic Properties) http://www.javapolis.com/confluence/display/JP06/Whiteboard+results+-+General+ideas.

    ReplyDelete
  4. I totally agree that referring to method through Strings doesn't scale on a serious project. But as we're talking about JDK7, the solution I think will come with a manner to reference a method in a static, compiler-checked way.

    Meanwhile defining properties as dedicated objects sounds the best to me. When I used the excellent Joda-time library (just noticed you're the author, congratulations) I felt very comfortable with its property system. Though I guess it means a lot of boring implementation code.

    I don't know if you heard about Scala, a fonctional / object-oriented language with strong Java bindings. As functions are first-class objects it's easy to implement properties without adding keywords. This is what the guys do propose:
    http://scala.epfl.ch/examples/files/properties.html

    ReplyDelete
  5. Stephen Colebourne8 January 2007 at 16:51

    @Ricky, I believe that a special syntax for accessing a property object might well make sense. But I see that as an addition to the base proposal. The most obvious choice is ironically the arrow pointer.

    binder.bind( person->surname );

    If you don't have the syntax, then users can simply call new SimpleProperty themselves and be no worse off than now.

    @Laurent, the property objects I'm proposing here are compiler checked, and auto-generated by the new property generation.

    I don't see compiled method references as the answer to this particular problem, as you need at a minimum a get and set method reference plus the bean to be invoked in order to create a full property.

    @Dobby, Glad you enjoyed the Javapolis whiteboards!

    ReplyDelete
  6. My company requires that member variables start with m_. I can just see it now.


    public void setM_Name(String m_Name) { this.m_Name = m_Name; }

    lovely.

    Get a life. add something of value to the language if you need to get your jollies.

    ReplyDelete
  7. One concern I have about the -> syntax is that it has a different meaning in C++, which could be confusing to people. I noticed that Cay Horstmann was using the @ symbol as an operator of sorts, though I'm not sold on that particular choice (shows up in some other languages as the attribute in an XML document).

    I'm not sold that we need to have a Property interface, because we already have the java.beans.PropertyDescriptor. If necessary, we could augment the PropertyDescriptor. True, PD doesn't have a reference to the instance.

    Your example code would become:

    binder.bind(person, Person->surname);

    Or some such thing. I'm using the -> even though I'm not particularly fond of it, just for consistency with the rest of your post.

    I've only vaguely thought about this problem so far. I'm hoping this might stimulate something in the conversation.

    ReplyDelete
  8. Richard, I don't think Property is analogous to java.beans.PropertyDescriptor. PropertyDescriptor is more like MetaProperty, not Property.

    I've also implemented something reasonably similar to Stephen's proposal in order to get increased type safety. My solution is driven by reflection, rather than code generation, which eliminates a compile step, but catches fewer errors at compile time.

    ReplyDelete
  9. Stephen Colebourne8 January 2007 at 21:47

    I've applied for a new sf project to host the updated Joda-Beans code so everyone can get a really good look, with proper documentation.

    @Richard, as Curt said, PropertyDescriptor maps to MetaProperty in my proposal. In fact, the standard implementation of MetaProperty uses a PD internally. Although having the reference to the bean in a Property object doesn't seem like much, it actually turns out to make the whole system a lot more OO and usable.

    @Sacrin, this post is about property objects. I don't care that much about the details of the syntax to get from your m_surname to propertySurname() except that it happens. Of course I'm not proposing propertyM_Surname(). Perhaps you'd care to blog about the language change you'd like instead?

    ReplyDelete
  10. Stephen,

    Could you go into a little more detail as to why you'd want the Property interface? Wouldn't PropertyDescriptor be enough? Who needs Property? Just frameworks?

    There's no doubting that foo->bar.get() would be better than foo->bar.getWriteMethod().invoke(foo). :-). I don't doubt it's better (even subjectively), but whether it is really necessary. I guess I've not yet bumped into it, so it isn't really essential to me, whereas you've no doubt bumped into it so it is necessary :-)

    I don't see the connection between the Property interface, and static connections to properties (such as binder.bind(foo->bar). Given a PropertyDescriptor, binding.bind() could do it's work).

    ReplyDelete
  11. Stephen Colebourne8 January 2007 at 23:31

    The principal reason for Property is that its just good OO design. You encapsulate the knowledge of the bean and property together in one object. We do it, because otherwise every other framework has to write a Property class that does the same task.

    A second reason is that it provides much better type safety and exception wrapping over calling invoke() on Method.

    Finally, there is no reason why the Property, MetaProperty, Bean and MetaBean interfaces have to be implemented by a normal JavaBean at all. They could be implemented using a HashMap to store the properties, or to front end a JDBC result set. This isn't a completely new area - Commons BeanUtis DynaBeans cover similar ground.

    ReplyDelete
  12. Stephen Colebourne9 January 2007 at 01:49

    The new sourceforge website for property objects is now up and running - http://joda-beans.sourceforge.net

    ReplyDelete
  13. Here are some advantages to Property objects:

    - If Property has listener support methods, you can turn run-time errors into compile-time errors
    - Multiple Property implementations mean the large number of different property implementation options doesn't pose a problem. See this blog for the problem being addressed:
    http://weblogs.java.net/blog/forax/archive/2007/01/property_and_be.html
    - Easy typesafe compile-time access to property metadata. Granted this is of much more interest to frameworks than "ordinary" code, but ordinary application developers sometimes have to do these things and/or spend time debugging frameworks.

    ReplyDelete
  14. Stephen, looks great. i posted this at javalobby - excuse me pasting it in here.

    Hiya Stephen,

    i like the "property objects" approach for "beans binding" and have presented this approach in a coupla articles (listed on "Gooey Beans"). i see my QProperty object is like your MetaProperty object. i haven't had a need for a Bean/Property object which binds a meta property/bean to a specific bean instance, although it does seem complete to do this, eg. your Bean, and maybe a BeanCollection, eg. for a JTable.

    In the case of the JTable for example, one would have a List of beans, and a single BeanInfo class with a Map of (Meta)Property objects. The TableModel invokes property.set(bean, value) and property.get(bean), where it references a Property object per column, and the bean for a given row in the table.

    What is your use case for exposing bound Property objects to the application, and invoking property.set(value) and get(), in the application code, rather than invoking setter on the bean?

    thanks
    evan

    ReplyDelete
  15. Stephen Colebourne9 January 2007 at 14:46

    @Evan, Yes, a JTable does consist of a MetaProperty per column and a Bean per row. The advantage of using Property when doing the evaluation of each cell is that the code is already written and encapsulated, and might not even point to a 'normal' JavaBean (direct database wrappers anyone?)

    You ask if an application would call property.get() or property.set(value) directly. The answer is probably not in the main body of the code, but you could easily write a method:

    public boolean validateMandatory(Property[String] property) {
    String str = property.get();
    return (str != null && str.length() > 0);
    }

    ReplyDelete
  16. Having worked with Properties in Delphi, all I can say is that if the following syntax doesn't exist, then the whole thing is just sugar-coating:

    public class Person {
    // pseudo code to define the property..
    property String FirstName;
    property String LastName;
    property Person[] FamilyMembers;
    }

    public class Tester {
    Person p0 = new Person();
    p0.FirstName = "Penny";
    p0.LastName = "Blonde";
    Person p1 = new Person();
    p1.FirstName = "James";
    p1.LastName = "Bond";
    p1.FamilyMembers[0] = p0;
    p0.FamilyMembers[0] = p1;
    }

    The idea is that the language should enable indexed-properties and access-syntax that does not have to directly rely on the set/get methods.

    Clearly indexed-properties present a problem if you do not have to define the size of the array and expect it to grow, but I'm sure code-generation under the hood can solve this issue as well.

    To sum up my point, if your properties are still accessed with get/set methods and not throw the property name alone, this isn't really any different than what we already have.

    ReplyDelete
  17. Stephen Colebourne10 January 2007 at 16:31

    @Doron, your definition of properties might be appropriate for Delphi, but it doesn't fit Java. Like it or not, Java does this using get and set methods, and so those will have to be supported.

    In addition, this blog/proposal is about accessing the property _object_ and meta property information, neither of which are addressed in your example.

    ReplyDelete
  18. @Stephen, I was trying to describe Properties as they should be (imo) implemented in Java and Delphi (imo) does it very well. Java supports Properties by way of Get/Set methods and so does Delphi, there is no reason why Java syntax should no evolve to include good patterns from other languages/technologies.

    About accessing the Property Metadata information or the Property Object itself, you're absolutely right, I didn't focus on those things because I didn't have anything to add to what was already said.

    ReplyDelete
  19. Stephen Colebourne16 January 2007 at 18:27

    @Doron, My latest post - http://jroller.com/page/scolebourne?entry=property_access_is_it_an - covers expression languages as one way to meet your requirements (which I've just understood on re-reading!). I think I agree that property access via get/set alone isn't enough of a change to be justified. List/Map access is also needed. Thanks for the good example ;-)

    ReplyDelete
  20. @Stephen, first, you're welcome. Secondly, I'll go read the other thread now :)

    ReplyDelete

Please be aware that by commenting you provide consent to associate your selected profile with your comment. Long comments or those with excessive links may be deleted by Blogger (not me!). All spam will be deleted.