 |
Say No to Properties Boilerplate!
Posted by cayhorstmann on June 08, 2006 at 04:15 PM | Comments (20)
Here is a simple code example from the JBoss EJB3
tutorial.
@Entity
public class LineItem implements java.io.Serializable
{
private int id;
private double subtotal;
private int quantity;
private String product;
private Order order;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public double getSubtotal()
{
return subtotal;
}
public void setSubtotal(double subtotal)
{
this.subtotal = subtotal;
}
public int getQuantity()
{
return quantity;
}
public void setQuantity(int quantity)
{
this.quantity = quantity;
}
public String getProduct()
{
return product;
}
public void setProduct(String product)
{
this.product = product;
}
@ManyToOne
@JoinColumn(name = "order_id")
public Order getOrder()
{
return order;
}
public void setOrder(Order order)
{
this.order = order;
}
}
64 lines.
Here is what you want to read:
@Entity
public class LineItem implements java.io.Serializable
{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
@Property private int id;
@Property private double subtotal;
@Property private int quantity;
@Property private String product;
@ManyToOne
@JoinColumn(name = "order_id")
@Property private Order order;@
}
12 lines.
That's only 20% of the original. The remaining 80% is boilerplate.

And that's not even counting the Javadoc!
There has to be a better way. My graduate student Alexandre Alves has
provided just that in his M.S. thesis. He
implemented
- an extension to the Mustang javac compiler
- a Javadoc doclet
- an optional annotation processor
- Ant tasks for all these
His tools support the @Property annotation of the preceding
example. Simply call his propjavac, and it synthesizes the
getters and setters and adds a Properties section to the Javadoc.
But wait, there's more. We give you syntax for accessing the
properties, almost like in JavaScript or Visual Basic:
LineItem item = new LineItem();
item.@subtotal = 100;
// calls item.setSubtotal(100)
em.persist(item);
int id = item.@id;
// calls item.getId()
We chose the .@ operator rather than the simple dot in JS/VB
so that there is no confusion with the field access item.id.
Alexandre worked out the pesky details with visibility, read-only
properties, BeanInfo, inheritance, and so on.
But there is still work to be done.
- If this is to be a feature of Dolphin, we can't use annotations to
generate the getters and setters. Annotations aren't supposed to modify
the file in which they are contained. It doesn't seem likely that we can
introduce a property keyword either. I suppose we could reuse
super . . . NOT. But what about
private int @id;
private Order @order; That's just a token, which doesn't break backwards
compatibility because you couldn't have an annotation at that spot. Too
subtle, or just right?
- Alexandre's property annotation has attributes for finetuning the
code generation, such as making read-only properties, package visible
getters and setters, etc. That's harder to do with just syntax. Does one
need these features, or should one go by the 80/20 rule? After all, one
can always write plain Java for the non-standard cases.
- The JavaBeans
specification has lots of seldom-used advanced features, such as
BeanInfo, indexed properties, property change listeners, and so on. Some
of them can be supported easily, others are trickier. I'll gladly
elaborate if anyone is interested. Does anyone use these regularly, and
if so, do you need boilerplate relief? For example, the JSP/JSF
EL doesn't even deal with indexed properties.
I really want native properties to happen in Dolphin. I am sick of the
boilerplate. Two years ago, I thought it would be too late, but I have
learned from EJB3 that Java can do the right thing...after we've tried
everything else.

Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
So the keyword (private in this case) refers to the visibility of the field and the automatic getters and setters get the same visibility as the class by default?
And in any other case I need to do it the old way? But then I don't get them listed as properties in Javadoc?
How about just letting the IDEs generate getters and setters and just modifying the javadoc generation when any of the getters and setters are present?
And/or perhaps borrow a bit more from other languages like this:
private int @id {
public get;
protected set;
};
in cases where you wish to override the defaults.
Posted by: tobega on June 08, 2006 at 10:18 PM
-
I agree with the first part, the introduction of @Property, but not the part of .@ operators:
The whole point of getters and setters is code encapsulation: you can refactor the contents of the getter field without having to break the public interface.
The compilers and the IDE should recognize @Property and treat it as if there is a getter and setter available. The @Property should have retention compile time, so there is no noticable difference with real getters and setters and runtime.
Getters and setters should be "in-class-overwritable" (for lack of a better term): if you define a getter/setter, the @Property is doesn't generate it.
An @Property is just as good as writing the getter and setters, so it can overwrite methods from superclasses, be warned.
PS: it should also be possible to only have a getter or only a setter: @Getter, @Setter or @Property (setter = false).
Posted by: ge0ffrey on June 09, 2006 at 12:35 AM
-
In your example, isn't
@Property private int id;
the same as
public int id;
I don't see any difference, execpt that you've actually added boilerplate for defining a public member.
Posted by: rufus on June 09, 2006 at 09:06 AM
-
Boy would this be nice.
I've wanted this for a LONG time. Ruby has something like it, only a bit better, where you can declare a readable/writable/both property.
Groovy has an @Property marker, though they may be in the process of changing it. It's very nice, though.
Posted by: trcorbin on June 09, 2006 at 09:11 AM
-
Cay,
Generally, setters are big trouble, but getters are not so bad (unless someone doesn't get DRY). Setters tend to mess with dirty bits, notify listeners, and have other wacky side effects, but getters rarely do. Luckily, "set exactly once after construction" is the 80% case (99.44% for my own code). Maybe start from something borrowed from Jython instead of J2EE:
LineItem item = new LineItem(subtotal=100, product="widget",quantity=4);
The intuitive meaning is clear, so there's less to learn (and no freakin' @s to preprocess). Plus I don't have to expose internal state to mutators after construction.
Posted by: dwalend on June 09, 2006 at 10:00 AM
-
Rufus: The code
@Property private int id;
is exactly equivalent to
private int id;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
Tobega: Having the IDE generate the getters and setters is not an optimal solution since you still have to read the boilerplate code.
Dwalend: Setters may be trouble, but they aren't easily avoided when you want to do dependency injection (e.g. in EJB3).
Keep those comments coming!
Cheers,
Cay
Posted by: cayhorstmann on June 09, 2006 at 08:56 PM
-
Excellent work. I hope something in this spirit would find it's way into Dolphin.
I think property change listeners and BeanInfo (or some other form of runtime accessible metadata) are very important for bindable component entities. We certainly use those for our generated beans. I'd be happy if you could elaborate on this kind of support.
In fact, I think there should be some support for generic interceptors on "getter"s and "setter"s, which may include firing property change events, invariants validation as well as other behavior "injection"
As for syntax, I prefer the C# way of accessing properties, using the ubiquitous dot notation. It is in line with various expression languages and doesn't require syntax changes. After all, accessing properties is a very frequent and not out of the ordinary operation in Java code, it shouldn't require syntax change. This can be implemented for example by introducing a bytecode-generated private field for each public property. I think introduction of new suntax notations should be sparse so that it's still possible to extend Java with more desired non-existing language features (such as escaping value evaluation in favor of reflection type information) without compromising Java's readaility.
I'd like to refer to Joe Nuxoll's aricle Java Properties and Events for some very interesting discussion on this topic.
Posted by: liqweed on June 10, 2006 at 10:18 PM
-
Yugh, I hate compilers and editors doubling as code generators, inserting stuff into my work that I've no control over.
Posted by: jwenting on June 11, 2006 at 11:19 PM
-
I hope a feature like this will be present in Dolphin. Danny Coward has written in his blog that he thinks it may be considered for Dolphin (you can read it here).
You can vote for this feature in this bugID.
Posted by: xmirog on June 12, 2006 at 12:34 AM
-
For this to be used in Swing applications, PropertyChangeEvents is an absolute must.
+1 on ge0ffrey's comments.
Posted by: neilweber on June 15, 2006 at 08:14 AM
-
This blog led to quite a few interesting comments (many quite emotional) at this JavaLobby thread..
Posted by: cayhorstmann on June 17, 2006 at 10:06 PM
-
Properties are one way, but what about:
@Getter and @Setter. These have optional parameters of enumtype Access, which comes in PACKAGE, PRIVATE, PROTECTED, and PUBLIC variants, with a PUBLIC default.
They generate the getter and setter as you would expect them.
In the extremely unlikely case you need to do more than just this.x = x; or return x;, you take out the Getter/Setter annotation and manually write the getter/setter.
Simple to understand, simple to implement, no new syntax, takes care of all the boilerplate.
Posted by: rzwitserloot on June 21, 2006 at 09:33 PM
-
You stole my idea. Just kidding, but please read my forum post on this:
http://forum.java.sun.com/thread.jspa?threadID=739931&messageID=4245147#4245147
I strongly agree with everything in this post. The annotation approach is easiest as it can be tacked on to the existing language with minimal compatibility issues. However, a true language feature would be a much better solution; in this case, it shouldn't use annotations at all or use a "@" annotation-like syntax.
To summarize some points:
- Getters/setters are easy to write, but a real hassle to read through, and maintain. Every time you change a field name or field type or add/delete a property, you must remember to update the getter/setters.
- Sometimes you need to add custom get/set logic without changing the public interface. This should be allowable as it is now. However 90%+ of the time, getters/setters just do the trvial set/return.
- Particularly with such property intensive frameworks as EJB3/JSF, this is a really important enhancement.
Posted by: gamigin on June 26, 2006 at 08:42 AM
-
I do not see the problem of having @Property at all !
I mean when you write for example is typing Foo.class is not accessing to the "class" field but accessing to a synthetic field created out of a kind of a "singleton pattern" created at the fly by the compiler.
Personally I agree with the code for taggying property, but about the calling code I would preffer to see :
LineItem item = new LineItem();
item#subtotal = 100;
// calls item.setSubtotal(100)
em.persist(item);
int id = item#id;
// calls item.getId()
I do preffer the # because it is close to the XML semantics and can also benefit the new XML integration dolphin is seeking at ...
I would love to see also an "action grammar" with method named doXxxxxx recognized as potential action to be used by user and that propose interraction with the related data. Having the synthax :
foo!activate (for instance in JSF expression) would be usefull to denote the reference to a particular action (for I18N, labelling, and activation purposes). But that is another topic ;-)
Posted by: bjb on July 13, 2006 at 06:44 AM
-
This is obviously a heated debate...
Firstly, I don't agree at all with the notion of annotations being for informative purposes only. This seems to be a perfectly valid use of annotations. I would rather ditch the @ in front of the access to those properties. I don't see why a field called hi and a property called hi is going to cause a problem. All you need to do is make a precedence to stick with and teach.
Now one argument against this method. Why don't the JSR people simply give up their angst and make an EXACT copy of the .NET way properties are created?
property Chillax{ get{} set{} }
Heck the compiler could even generate legacy getters and setters. This is the last thing I think Java needs.
Posted by: coding on July 14, 2006 at 11:43 AM
-
I'm not sure I undestood the problem, so maybe this is a stupid question...
If the @Property would clear the code inside the class by suppressing the getters and setters boilerplate code, then I supose there is no usefull code at all inside those getters and setters.
Why not just make those attributes public?
Or
What good would be a @Property annotation when we need to put some business code inside the getters and setters?
Regards,
Charles Abreu
Posted by: charlesabreu on September 12, 2006 at 11:04 AM
-
Some times ago, I searched for a solution like the one describe. But I wanted a solution ready for jdk 1.5 (and if possible for jdk 1.4). And after some night (of reading, studing, try,...), I found not one solution but a combinaison of solution. So no more need to write or generate getXxxx() and setXxxx(...). I keep my code clean and clear :
- Use public attribute as property, instead of private attribute and accessor methods.
- When I use framework/lib that can't access property without get/set, I use GetAndSetAdder to generate basic public getter/setter on bytecode. Like that, reflection based lib will continue to work. (It's a tool I wrote and publish)
- When I'll want to add behavior when properties are accessed, I'll use AOP to add extra stuff before/after reading/writing attribute.
You could saw Faq to learn why it's a working/viable solution, description of the problem and our solution, and others approaches to compare. We expect that after explore our solution (reading documentation, faq,...), you ask yourself : "Why using getter and setter ?"
take a look at http://alchim.sf.net/getset. Every comments are welcome.
Posted by: dwayne31 on September 19, 2006 at 07:01 AM
-
I agree with rufus and dwayne31. When will this getter/setter-mania end? Here is another nice article on the topic: http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
Posted by: hixxxxx on November 09, 2006 at 03:41 AM
-
Wow, I'm a year late, but I also recently wrote a similar @Property annotation, this time based on JSR269, the Tree API and a little bit of access to javac internals. This should pretty much work transparently on netbeans 6, and I need to do some hacking to get this to work with eclipse (3.3, JDT will have jsr269 support).
I didn't bother with the @ property operator as I don't mind using get/set directly. It's also too much of a change to the language to be readily used across IDEs, etc.
http://www.hanhuy.com/pfn/java_property_annotation
http://svntrac.hanhuy.com/repo/browser/hanhuy/trunk/panno
Posted by: pfnguyen on May 15, 2007 at 03:53 PM
|