Tuesday, February 16, 2010

Understading some of Roo's magic

  I must admit that I was among the many developers I know who are very skeptical about Aspect Oriented Programming (AOP).  I've written many aspects myself, some which I now define as "entry-level".  I had not seen a clear use-case for aspects other than the basic "auditing", "logging" or "security" use cases.  So, a few months ago I started to play with one of the latest tools from SpringSource, namely Spring-Roo. To my surprise, Roo was not only meeting my expectations, but also made me a believer on yet another good use case for AOP.  The use case of tooling support.  I'll try to explain some of the magic which Roo brings to software development using AspectJ.

Consider for a moment the following entity:

public class MyPojo {
  private String name;
}

This entity can easily be coded using any IDE, however Roo allows you to create it with a command line shell. Once this is done, the average developer will rely on source generation features (from an IDE) to generate Setter/Getters (so as to conform with standard JavaBean conventions). This is where the concept of Inter-Type Declarations (ITD) in AspectJ can be of great help.  Consider the following aspect:
public aspect MyPojo_Entity {
  private Long id;
  private static int sequence = 0;
  
  /** 
   * Constructor with arguments
   */
  public MyPojo.new(String name) {
    super();
    id = new Long(sequence++);
  }
   
  /**
   * ToString method.
   */
  public String MyPojo.toString() {
    return "Sequence: " + id;
  }
}

You can see that this aspect is now introducing  a new constructor as well as a toString() method for the entity MyPojo. The resulting bytecode will now have a toString() method which can be called anywhere. Also, it will enforce the constructor to be called with an argument. This notion of ITD can be used to introduce new methods as well as private properties. Now, let's finish this aspect:

public privileged aspect MyPojo_Entity {
  private Long MyPojo.id; 
  private static int sequence = 0;

  /**
   * Constructor
   */ 
  public MyPojo.new(String name) {
    super();
    this.name = name;
    this.id = new Long(sequence++);
  }
 
  /**
   * Retrieves the id of this pojo
   */ 
  public Long MyPojo.getId() {
    return id;
  }

  /**
   * Retrieves the name of this pojo
   * @return the name of this pojo.
   */ 
  public String MyPojo.getName() {
    return this.name;
  }
 
  /**
   * Sets the name of this pojo.
   * @param name the name to set.
   */ 
  public void MyPojo.setName(String name) {
    this.name = name;
  }
 
  /**
   * Default toString() method.
   */ 
  public String MyPojo.toString() {
    return "Pojo [id="+this.id+"]: " 
          + this.name;
  }
}

As you can see,  we not only introduced the methods needed to make MyPojo compliant with JavaBean standards, but also added more attributes and methods (e.g. to help persisting it). Furthermore, if you look closer, the aspect definition now uses the privileged keyword. A privileged aspect basically grants access to private attributes and methods of the class in question, thus we can use the this.name for this purposes without problems.

If you look at the generated code from Roo, this is exactly how Roo makes magic happen. In fact, Roo also injects an EntityManager as well as hashCode(), equals(), as well as other methods based on the cross-cutting concern. It's defitenetly worth checking out Roo for a good test-drive, not only of the tool, but how to use AspectJ effectively.

No comments: