Naked Objects and AOP - Part 2

Last month I wrote about the potential synergy between Naked Objects and AOP.  Since then I’ve conducted my first crude experiments with Aspect and the AJDT plug-in for Eclipse.  (I found the latter remarkably straightforward to install and use).

 The first of my suggested uses for AOP within Naked Objects was to eliminate the need for adding resolve() and objectChanged() calls within your properties.  I managed to get this working, and I’ve posted the code below for anyone who’d like to try it out.

 (As I’ve made clear, I’m a complete beginner at AOP, so if anyone more experienced in that technology can see anything wrong with this code, or any improvements, please do post a comment.)

Richard

import org.aspectj.lang.reflect.MethodSignature;

import org.nakedobjects.applib.DomainObjectContainer;

 

public aspect ResolveAndObjectChanged {

 

// {{ Define the ContainerAwareObject interface and its methods

 

public interface ContainerAwareObject {}

 

private void ContainerAwareObject.objectChanged() {    container.objectChanged(this);

}

 

private void ContainerAwareObject.resolve(Object object) {

    container.resolve(object);

}

 

private DomainObjectContainer ContainerAwareObject.container;

 

// Naked Objects will inject a DomainObjectContainer here

public void ContainerAwareObject.setContainer(

    DomainObjectContainer container) {

    this.container = container;

}

// }}

 

// {{ Declare domain classes that should implement ContainerAwareObject

declare parents : projectname.dom.* implements ContainerAwareObject;

// }}

 

// {{ Define the objectChanged pointcut and advice

pointcut objectChanged(ContainerAwareObject target, Object objectBeingSet):execution(void ContainerAwareObject+.set*(..)) && target(target) && args(objectBeingSet);

 

after(ContainerAwareObject target, Object objectBeingSet): objectChanged(target, objectBeingSet) {

    if (objectBeingSet instanceof DomainObjectContainer) {

        return; // Don’t call objectChanged() within setContainer() method;

    }

    target.objectChanged();

    System.out.println(“objectChanged() called.”);

}

// }}

 

// {{ Define the resolve pointcut and advice

pointcut resolve(ContainerAwareObject target): execution(* ContainerAwareObject+.get*()) && target(target);

 

before(ContainerAwareObject target): resolve(target) {

 

    /*

    * This implementation assumes that the convention has been followed

    * that getters and setters have the same name as the private variable.

    * The following code determines the private variable name from the

    * getter/setter.

*/

    try {        MethodSignature ms = ((MethodSignature) thisJoinPointStaticPart.getSignature());

        String propertyName = ms.getName().substring(3);

        String variableName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1, propertyName.length());

 

        Class targetClass = target.getClass();

        Object var = targetClass.getDeclaredField(variableName);

        target.resolve(var);

        System.out.println(var + ” resolved.”);

 

    } catch (NoSuchFieldException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    }

}

// }}

}

3 Comments so far

  1. Jan Lessner on October 23rd, 2007

    I’m afraid it’s not as simple as you proposed. One problem is that you just instrumented the set… methods of the domain object classes, but there ars certainly others to consider too, like addTo… and remove… Even more difficult to achieve is the exclusion of methods being concerned with dependency injection. In your example you are explicitely excluding setters which get passed a DomainObjectContainer which is fairly simple. But what’s about other services and factories/repositories which are not known at compile time of the aspects? The exclusion mechanism needs to know about these too, e.g. by parsing them out of nakedobjects.properties. Additionally I understood your solution being based on the idea that the domain classes of interest are supposed to implement a common interface ContainerAwareObject. I believe that this will not be excepted by people who are moving to a POJO approach in other technologies like EJB and JPA.

  2. Richard Pawson on October 23rd, 2007

    I was just trying to demonstrate the concept, in order to get the ball rolling. You are certainly correct about needing to include the addToXxx and removeFromXxx methods. Likely you would need quite a few aspects to build a complete solution this way, including the one for intercepting the construction of new object. (Dan pointed out, correctly, that I should also have split even this aspect into two: one that defined the ContainerAwareObject and one that implemented the objectChanged() and resolve()).

    In regard to injected dependencies (other than the container) I’m not sure there’s a problem there. Robert advises me that calling objectChanged() within the setter for an injected dependency (e.g. a Repository or other type of service) should not, in general, cause a problem (that said, I haven’t tried that out yet). I had to put in the guard against the injection of the DomainObjectContainer, though, because calling objectChanged() there caused a circularity.

    On your last comment I think you might have a misunderstanding. My solution does NOT require that your domain objects implement ContainerAwareObject explicitly - that implementation is done by the aspect at compile time. In other words you should still be able to use a POJO domain object without modifying the code.

  3. […] Also wieder einmal das Rad zu spät erfunden. Wikipedia führt sogar noch weitere Raderfinder, oder zumindest Radbauer auf. Aber auch wenn ich wohl nicht als Erfinder in die Analen der Softwareentwicklung eingehen werde, halte ich das Konzept für einen hoch interessanten Ansatz, bei dem es aber sicher noch eine Menge zu tun gibt. Ich bin zum Beispiel weder von der generierten GUI von Naked Objects 100% überzeugt, noch von dem Ansatz wirklich 100% zu generieren. Mindestens für eine Übergangszeit halte ich es für absolut wichtig immer noch die Möglichkeit zu haben einfache einen Dialog zu öffnen und den eigenen GUI-Code dort zu verewigen. Ich werde das Projekt und das Blog von Richard Pawson jedenfalls weiter beobachten, in dem er unter anderem über neue Ideen für das Framework schreibt. […]

Leave a reply