The morning after

Sunday, June 18, 2006

Code generation and AOP

In most, if not all, of my projects I am making use of AndroMDA in order to get the boilerplate code generated for me, this works great but sometimes I'll find myself customizing the cartridges to fit the architecture/design, in this entry I will give an simple example replacing AndroMDA-generated logic with AOP using AspectJ.

As an example take the case of the Hibernate entities: AndroMDA generates an abstract base class and a concrete subclass suited for implementation. The subclass will be generated only once so that you can safely add your implementation for business operations without the generation process overwriting it each time you run AndroMDA.

This is an example of an abstract base class:

public abstract class Entity
{
...
public abstract void myOperation(String value);
...
}

And here is an example of an implementation:

public class EntityImpl extends Entity
{
...
public void myOperation(String value)
{
// todo: implement
throw new UnsupportedOperationException("EntityImpl.myOperation");
}
...
}

This means, however, that when you are making use of Hibernate inheritance the hierarchy can get rather deep, it would be nice if this could be avoided.. And it can!

The trick is to make use of AspectJ, with this it is possible to only have the base class as a concrete class and not generating the *Impl class; the business operations still throw an exception as shown above but this behavior can be overridden by an aspect advice.

public aspect EntityAspect
{
void around(String value, Entity entity) :
execution(* Entity.myOperation(String)) && this(entity) && args(value)
{
// here you can implement the new logic
// value = the argument passed in
// entity = 'this'
}
}

Having such an aspect woven in will replace the generated method implementation entirely (without removing it though), thus effectively annulling the exception. As far as I know this can only be achieved as elegantly as presented here by making use of the around() advice.

Note that it is still possible to call the original implementation by making use of proceed()

Considering the different possibilities for merging in your own code in generated code somehow (protected sections, inheritance, etc..) I think this is a nice alternative. One could argue that it is more interesting to have such implementation inside the generated .java file but trying to enforce this will result in not-so-elegant situations considering you'll want to regenerate the class each time while retaining you're custom implementation.

0 Comments:

Post a Comment

<< Home