Table of Contents |
---|
Why typed properties?
One of the banes of Java is the abomination we call properties: the sad convention that gives us getters, setters and strings to access them. Using strings to access properties is a disaster because with one fell sweep all that work that the compiler does to check everything is useless: using a string means all errors will occur at runtime. And forget about refactoring: renaming properties is an exercise in frustration as even with the high level of support for refactoring in IDE's property references in strings will still bring your code down.
...
Many frameworks have the above problem, so there are many solutions. The JPA 2.0 Criteria API has a specification for a domain class processor where an annotation processor is used to generate typed properties for all Entity classes in the JPA model. Libraries like queryDSL have a similar approach where a processor or a Maven plugin generates special classes for your entities, allowing you to write SQL in a reasonably intuitive and typesafe way. The problem with all of these is that they service a very specific area of the problem: they are defined for database entities. But any Java class that is part of a model can need typed properties, not just database related classes. So we need something more "generic".
Using typed properties in code
In code you use typed properties at all locations where you would usually use a string containing some property path. For example:
Code Block |
---|
List<Album> query = dc().query(QCriteria.create(Album.class).eq(Album_.artist().name(), "AC/DC")); System.out.println("Got " + query.size() + " results"); |
The stanza Album_.artist().name() is a typed property reference. The Album_ class is generated automatically by an annotations processor, for all classes annotated by either @GenerateProperties or @Entity. The result of a property reference is QField<I, V>, where I stands for the class that the property reference comes from (Album in the above case) and V stands for the type of the property itself (which would be String in the above example because the "name" property of the Artist class is of type String.
Another example is for instance in data binding:
Code Block |
---|
ComboFixed2<AmountType> bedragTypeCombo = ComboFixed2.createEnumCombo(AmountType.class);
bedragTypeCombo.bind().to(row, Line_.amountType());
bedragTypeCombo.bind("readOnly").to(model(), LineController_.readOnly());
bedragTypeCombo.setMandatory(true);
bedragTypeCombo.immediate(); |
Here we bind the readOnly property of the control (still by string here) to the LineController.isReadOnly() method, and the value of the control to Line.amountType.
The annotator does not annotate controls because that would cause a lot of useless work. Instead all DomUI controls have typed properties inside the class itself for all control properties for which binding is a reasonable idea. So to fix the above string we need to change the line to:
Code Block |
---|
bedragTypeCombo.bind(ComboFixed.READONLY).to(model(), LineController_.readOnly()); |
Enter the typed properties annotation processor.
Because having just one wheel is not that useful: let's invent yet another one. The DomUI property-annotations-processor is an annotation processor which will create special classes for each class that we use in a model. It generates only classes with typeful properties; it does not add "natural query" ability or whatever.
...