Thursday, August 26, 2010

Context dependent annotations

This actually started as a discussion between myself and a former colleague. He was saying that he was leaning away from annotations. Given that he's the kind of guy who loves all things annotations, I was intrigued as to why.

Turns out in his project there's a common domain object used by a variety of sub projects; which he wanted to reuse. One dev had annotated the class with JAXB annotations to convert the domain model into a XML representation for another sub project. Another dev had annotated it with JPA annotations to obviously persist the model. When my mate came along just wanting to simply use the POJO, all these dependencies came along with it. Which made me realise during his whinge to me (:p), that annotations are really context dependent because of both the compile time and (most times) runtime dependency on the annotation JAR. This highlighted to me one of the best advantages of an XML "descriptor". If it's there, meta data is added (such as persistence information), if not, the code will still actually run on it's own.

"But hey, part of the behaviour is that it is persisted (or whatever)". Which is true, but another way to think about it is that the annotations force the code to act in a certain "layer". For example you don't just throw domain objects at a database. You usually have some code in there that determines what sort of access other parts of the application has. So it's the responsibility of that layer (in this case the Persistence Layer) to provide the mapping detail between the domain model (as a Java class) and the other representation; which probably is a row in a table in a relational database. The same approach can be taken for your View Layer which might aggregate multiple discrete pieces of domain data into something that is consumed by another application. JAXB marshalling can help here.

What my mate suggested was that in the relevant layer (back to Persistence we go) you extend the class and annotate the extension. But I feel this is ugly as to get it to compile you may have to change the access scopes of class attribute. If Foo has a private string, and AnnotatedFoo extends Foo - no string for you. With reflection we can get around this though, which is what most frameworks use anyway. I feel XML descriptors are the better solution. Pull in Foo which is in a JAR that can be used by anybody, then use the class in the way you want adding the extra behaviour through the descriptor mappings. This way Foo can be left context free. Bundle FooJar with DAOJar in a WAR or EAR with descriptor.xml and you're done.

On the flip side there is a perfectly reasonable trade off for using annotations, if you want to sacrifice that portability. An example of this is Spring AOP. You might want to never operate your code outside a Spring container, and thus to gain the benefits of AOP, you can easily use the annotations. That's a trade off I'd be willing to make in my persistence layer for example, but not in my domain model (although I can't think of a reason why you'd need AOP in a domain model).

I'm not anti annotations, but realising that they bind my code to a particular context means that I have to be really careful using them to facilitate other developers who might want to use the POJO in a different context.

No comments:

Post a Comment