I don't have to repeat them!
I'll just add a few links:
- The kijaro project has the first version of Remi Forax's Property implementation.
- The google doc by Remi that documents this first usage of property as a language feature (as far as I know it's the only one).
- The usage of this implementation with Beans Binding in Remi's blog entry.
The benefits of using abstract enum to enumerate properties are:
- Easy and type-safe properties introspection: MyClass.Property.values() returns the collection of MyClass.Property<MyClass,?>;
- Easy and type safe conversion from a string to a property object: MyClass.Property.valueOf("firstName") returns MyClass.Property<MyClass,String> MyClass#firstName;
- I can switch (aProperty) {case firstName:...};
- MyClass#myProperty is an instance of MyClass.Property and so I can use == comparator with no risk.
- I can use MyClass#myProperty in annotations that accept the abstract Enum PropertyAdaptor as parameter. Things like @LinkTo(Person#firstName).
public class Person {Analyzing the syntactic sugar generated by Remi's implementation, I needed to clarify where are the Type1 (Bean-independent property: aka per-class, property-proxy, property adaptor) and Type2 (Bean-attached property: aka per-instance) properties classes and instances. These types are nicely defined in Stephen Colebourne's blog Java 7 - Properties terminology. Remi calls the Type1 a "Property Literal" and it is implemented with an anonymous class inheriting from a new class in the JDK: java.lang.Property.
public property String firstName;
public property String lastName;
public property int age;
}
For Type2 there is no need for a class since the basic property boilerplate code generated is:
private String firstName;The above code is the syntactic sugar created by javac, and so not editable in any way. For the Type1 the generated code is:
public String getFirstName() {return firstName;}
public void setFirstName(String param) {firstName = param;}
public static Property<Person, String> firstName() {And for Bean introspection (getting the list of properties) another piece is generated:
return new Property<Person, String>(
"firstName",
String.class,
Person.class) {
public String get(Person person) {return person.getFirstName();}
public void set(Person person, String s) {person.setFirstName(s);}
};
}
public static Property<Person,?>[] properties() {return $PROPERTIES;};This is the code for a basic property, but there are more features implemented like:
private static Property<Person,?>[] $PROPERTIES = new Property[]{firstName(),lastName(),age()};
- Generating a getter method only or a setter method only
- Implementing getter and setter inline of the property declaration
- And the very powerful 'bound' which allows automatic events on setXXX() without boilerplate code.
public class Person {Here is the generated code:
public property String firstName;
public property String lastName get { return "XXX"; };
public property int age bound;
protected <B,T> void propertyChanged(java.lang.Property<B,T> property,Object oldValue,Object newValue) {
System.out.println("property changed "+property+" "+oldValue+" "+newValue);
}
}
public String getLastName() {return "XXX";}That's a lot of syntactic sugar, but that's the point of properties, isn't it: Value objects WTF!!?!!2!. This property implementation works very well for Swing and Beans Binding implementation like Remi's demo shows. You can also write very quickly generic equals and hashcode methods based on the properties list. But, as a backend developer I also need properties.
public static Property<Person, String> lastName() {
return new Property<Person, String>(
"lastName",
String.class,
Person.class) {
public String get(Person person) {return person.getLastName();}
public void set(Person person, String s) {throw new UnsupportedOperationException();}
};
}
private int age;
public int getAge() {return age;}
public void setAge(int param) {
int oldValue = age;
age = param;
this.<Person,Integer>propertyChanged(age(),oldValue,param);
}
public static Property<Person, Integer> age() {
return new Property<Person, Integer>(
"age",
int.class,
Person.class) {
public Integer get(Person person) {return person.getAge();}
public void set(Person person, Integer s) {person.setAge(s);}
};
}
Property as language feature is not just syntactic sugar generation it's really solving a problem that just CANNOT be solved in Java today: How can I safely (which means maintaining type safety) pass a field or method (which are the elements that represent a property today - getter/setter) to a framework like JPA, WebBeans, Validations framework, Wicket, Swing Bindings, and all the others developed out there? Today, you NEED to pass a String (EL) and do reflection. That does not make sense. When I know a UI component is bound to Person.firstName, why do I need to write bind(Person.class, "firstName") and loose type safety, compiler existence check (whether or not firstName property exists), and so refactoring ability.
Next post, I'll expose how I wish to have properties for all ;-)
2 comments:
There appears to be an error in the last bit of code where you have mixed up firstName and lastName properties.
Otherwise interesting post. I like it.
Thanks.
Fixed the error (I think ;-)
Post a Comment