Java Annotations - Java's love of configuration over convention

March 11, 2009

Join my mailing list…

In the beginning, EJB was a bloated mess of XML configuration files that allowed some sort of ultimate flexibility that absolutely no one needed nor cared about. And it sucked. So developers started using conventions to keep track of the four classes required to make a remote method call, and XDoclet was created to automate the creation of the XML configuration files. And it sucked less. Following in EJB's footsteps, Hibernate did the same thing. And XDoclet followed. And it still sucked.

So, annotations were created to essentially formalize what XDoclet was doing, instead of considering how horribly broken the implementation of J2EE or Hibernate was. And now that we have annotations, the "implementation pattern" of "ultimate flexibility through annotations" has made its way into numerous Java frameworks, such as JAX-RS and JPA.

Regarding JPA:

@Id
@GeneratedValue
@Column(name="person_id")
public int getPersonId() { return personId; }
This is not a significant improvement over XDoclet; the only benefit is if you mistype "GeneratedValue", the compiler will catch it. I shouldn't have to type "GeneratedValue" in the first place. Unless I'm doing something non-standard. Which I almost never do.

I have a Person class with a getPersonId method. Can JPA just assume that it maps to the PERSON table, and the PERSON_ID, respectively. Further, couldn't it figure out that it's the auto-generated primary key since the schema says primary key auto increment. All the information is there and available to the framework to figure this out.

The same goes for EJB. I have a class named FooStatelessBean. How about we assume it's a stateless session bean, and it's interface is defined by its public methods? It can then provide FooRemote and FooLocal for me, and I don't need to configure anything or keep three classes in sync.

Just because Java doesn't have all the Ruby dynamic magic doesn't mean we can't make things easy. In reading Surya Suravarapu’s blog post about CRUD via JAX-RS I can't help wondering why it takes so much code to call a few methods on a class?

Did the designers of JAX-RS not even look at how Rails does things? I get a PUT to the url /customers/45. We should default to calling put(45) on the class CustomersResource. Only if I want to obfuscate what's going (e.g. by having FooBar.frobnosticate() handle the request) should I be required to provide configuration.

Even in Surya's example code, he's following some conventions: His resource class is suffixed with Resource and his POST method is prefixed add. This should be baked into the spec. It's like EJB all over again with the common conventions that aren't supported by the framework because of too much useless flexibilty.

Supporting convention over configuration is easy in Java. In just a few hours, I had a tiny web framework that proves it1. It wouldn't take much more effort to allow the default behavior to be overridden, but, unlike JAX-RS, EJB, or even the Servlet spec itself, it doesn't punish developers who follow conventions. It makes their lives easier and thus encourages good behavior.

So, the point of all this is that annotations encourage bad framework design; unnecessary configuration is a major part of many Java frameworks and specs. And I have no idea why.


1it unfortunately breaks down at the UI layer, due to a statically typed and compiled language not being a great choice for implementing web UIs, but that's another issue.