The Source for Java Technology Collaboration
User: Password:



   

Writing Mixins using AspectJ Writing Mixins using AspectJ

by Mohan Radhakrishnan
12/15/2005

Contents
AspectJ Tooling
Crosscutting Concern
What Exactly Is a Mixin?
Inter-Type Declarations
or Introductions
The AOP Implementation
Without Mixins
AOP Mixin Implementation
AOP Mixin Implementation
with AspectJ 5 and JSE 5.0
Incremental Compilation Bug
Conclusion
Resources

Aspect-oriented programming complements object-oriented programming in many ways. One interesting complementary feature is behavior composability. This means that it should be possible to compose a class by adding behavior from different classes. OO uses inheritance and many patterns to add behavior to existing classes. AOP allows us to use mixins without changing the class inheritance hierarchy or otherwise changing the code.

Mixins enable us to uniformly extend a set of classes with a set of fields and methods. Java does not support mixin-based programming. This article shows what mixins are and explains how AOP constructs in AspectJ allow us to use this technique to isolate crosscutting concerns, with an example. It starts with a plain Java implementation and ends with an AspectJ 5 implementation.

AspectJ Tooling

AspectJ programs can be compiled either using the command-line compiler ajc, which is included in the AspectJ distribution, or by using better tooling support in the form of AspectJ Development Tools for Eclipse (AJDT). All of the benefits of an Integrated Development Environment are now also available for AspectJ projects. I used the latest versions of Eclipse and AJDT to compile these examples, which, as of the writing of this article, were Eclipse 3.1.1 and AJDT 1.2. See the Resources section for a very good description of AJDT and how to create AspectJ projects in Eclipse.

Crosscutting Concern

A class is the fundamental unit of manipulation in Java. Concerns that crosscut this modular unit could be isolated so that such code is not spread out across the codebase. This will make their modification easier. It should also be easy to add a concern without changing the code that this will affect.

Our crosscutting concern is the notification of changes to Java bean properties. JavaBeans can have bound properties. This means that we can register listeners to get notification when the value of the property changes. The java.beans package contains the classes and interfaces required to implement this functionality.

The following code shows the plain Java implementation.


import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;

public class Bean implements Serializable {

    private String name;

    private PropertyChangeSupport support =
                    new  PropertyChangeSupport(this);

    public void addPropertyChangeListener
                       (PropertyChangeListener listener){

            support.addPropertyChangeListener(listener);

    }

    public void addPropertyChangeListener
                            ( String propertyName,
                  PropertyChangeListener listener){

            support.addPropertyChangeListener(propertyName,
                                              listener);

    }

    public void removePropertyChangeListener
                            ( String propertyName,
              PropertyChangeListener listener) {

            support.removePropertyChangeListener( propertyName,
                                                  listener);

    }

    public void removePropertyChangeListener
                            (PropertyChangeListener listener) {

            support.removePropertyChangeListener(listener);

    }

    public void hasListeners( String propertyName ) {

            support.hasListeners(propertyName);

    }

    void firePropertyChange( Bean b,
                             String property,
                             String oldval,
                             String newval) {

            support.firePropertyChange( property,
                                        ( oldval == null ) ?
                                              oldval :
                                              new String(oldval),
                                              new String(newval));

    }

    public String getName() {

            return name;

    }

    public void setName( String name ) {

            firePropertyChange( this,
                                "name",
                                getName(),
                                name );
            this.name = name;

    }
}

The important points in the code are:
  • We can delegate listener maintenance tasks to the PropertyChangeSupport class.
  • The firePropertyChange method, which is called after the property changes, notifies the PropertyChangeListeners.
The code shown above mixes event listener code with a simple Java bean that declares properties and getter and setter methods for them. We could separate the event listener concern into a separate class that all JavaBeans must extend, but that does not ensure that the concern is truly separable. It is still linked by the OO inheritance hierarchy. This is where AOP complements OO, by introducing the concept of a mixin, which is not properly addressed by an object-oriented language like Java.

The following is the JUnit test case based on the self-shunt pattern (see Resources).


import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import junit.framework.TestCase;

public class BeanTestCase extends TestCase
                 implements PropertyChangeListener{

       private String lastName;

       public void setUp() throws Exception{
               super.setUp();
       }

       public void TearDown() throws Exception{
               super.setUp();
       }

    public void propertyChange(PropertyChangeEvent e){
        System.out.println("Property [" +
                           e.getPropertyName() +
                           "[ changed from " +
                           e.getOldValue() + " to " +
                           e.getNewValue() );
         lastName = e.getNewValue() == null ? null :
                                 (String)e.getNewValue();
   }

       public void testPropertyChange(){
               Bean b = new Bean();
               b.addPropertyChangeListener( "name", this );
               b.setName( "Test" );
           if( lastName != null )assertEquals( b.getName() ,
                                               lastName );
           b.setName( "Test1" );
           if( lastName != null )assertEquals( b.getName() ,
                                           lastName );
       }
}

The JUnit TestCase shown above registers itself as a PropertyChangeListener so that when the bound property changes, it is notified via a propertyChange(PropertyChangeEvent e) method that is called. The parameter PropertyChangeEvent contains both the old and the new values. This test case plays the role of the listener, thereby obviating the need for a separate listener.

Now let us see how aspect-oriented mixin programming enables us to specify crosscutting concerns in one place and compose them with existing classes without changing the Java code.

Pages: 1, 2, 3, 4

Next Page » 

View all java.net Articles.

 Feed java.net RSS Feeds