Wednesday, May 19, 2010

AspectJ Inter-type Declaration

AspectJ is a very powerful AOP framework. It's most commonly used for logging, security, transaction, etc. Besides that, AspectJ has a powerful feature that allows you to add a method or a field to a class, or declare a type that implement an interface. I will show you how it can be done in AspectJ.

Here, we intend to add a new method, called sayBye(String message) into HelloWorld.
HelloWorld.java
package myproject;

public class HelloWorld {

    public void sayHello(String message) {
        System.out.println(message);
    }
}

We create a new interface called ByeWorld and make HelloWorld class to implement it.
ByeWorldAspect.aj
package myproject;

public aspect ByeWorldAspect {

    declare parents: HelloWorld implements ByeWorld;

    public void ByeWorld.sayBye(String message) {
        System.out.println(message);
    }

    before(ByeWorld byeWorld)
        : execution(* ByeWorld+.*(..))
            && !execution(* ByeWorld.*(..))
            && this(byeWorld) {
    }

    private static interface ByeWorld {
    }
}

Main.java
package myproject;

public class Main {

    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.sayHello("Hello World!");
        helloWorld.sayBye("Bye World!"); // There is no sayBye() in HelloWorld class!
    }
}

Make sure you add failOnError to true in the maven-compiler-plugin.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>myproject</groupId>
    <artifactId>aspectj-project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.7</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6<source>
                    <target>1.6</target>
                    <failOnError>false</failOnError>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <source>1.6</source>
                            <target>1.6</target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>myproject.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Although this feature is very powerful, my advice is not to overuse it because it can lead your code into an unmaintainable state. Remember, great power comes with great responsibility :)

No comments:

Post a Comment