Saturday, 25 June 2011

The Annotation Paradigm Shift

One of the current paradigm shifts in the Java world is to update existing APIs that were originally based on inheritance and replace them with much the same API only this time based on annotations.

For example, EJB 2.x used inheritance,

public interface WineSearchFacade extends javax.ejb.EJBObject {

or in terms of Spring 2.5...

public class WineSearchFacadeBean extends AbstractStatelessSessionBean implements WineSearchFacade, WineSearchFacadeLocal {

where as EJB3 uses annotations to do the same thing:

@Stateless(name = "WineSearchFacade", mappedName = "WineSearch")
public class WineSearchFacadeBean implements WineSearchFacade, WineSearchFacadeLocal {

...and similarly JUnit 3 used inheritance:

  public class FileUtilTest extends TestCase {
public void testFileCopy()  {

and JUnit 4 uses annotations:

  public class FileUtilTest {
public void testFileCopy()  {

Likewise Spring 2 MVC favoured inheritance...

public class SearchController extends SimpleFormController {

and Spring 3 MVC...

public class SearchController {

So, why do API developers do it? It’s a new API for your users to learn - but then programmers like learning new things (or at least they should). It should simplify writing your code, true in the case of JUnit: with JUnit3, you had to remember the rule that every test method had to start with the word ‘test’, all you do now is annotation your method with @Test and any method name will do (although I’ve noticed most programmers still prefix test methods with the word test).

Does it always simplify things? Take EJB3 MDBs, in a previous blog I commented that the annotations were woolly and imprecise with annotation attributes using such weasel words as propertyValue and propertyName without these values being well defined and how that was worse than using XML because with XML you have the schema file to refer to.

@MessageDriven(name = "myBasicMDB", mappedName = "jms/BasicTestQueue", activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destinationName", propertyValue = "jms/BasicTestQueue") })
public class BasicMessageDrivenBean implements MessageListener etc.

Are APIs that use inheritance too difficult to use? Not really, all you need to know is to use the extends keyword; however, it is true that APIs which use inheritance tend to come with a whole set of additional rules in the form of requiring you to add boiler plate code or implement certain abstract methods, which could be messy and repetitive. Annotations are the exact opposite of this: annotated classes are lighter and smaller than their inheritance counterparts and on the whole simpler.

Does using annotations given you any additional benefits if you’re the API programmer? Using annotations means that the code which reads annotations is highly extensible and decoupled from its annotated client code. An API programmer can change the code that reads your annotations without breaking your code. Inheritance is far more brittle when it comes to this type of extension and change.

I like to think of annotations as a form of aggregation as a class that reads annotations is really creating references to other objects and their methods and a Joshua Bloch rule is to always favour aggregation over inheritance.

Annotations are a very powerful tool, but I do wonder if they’re a solution that’s been looking for a problem and has suddenly found one.

No comments: