jakub holý

building the right thing, building it right, fast

Compiling with AspectJ''s ajc compiler from Maven

2009-12-10Languages

I needed to compile AspectJ classes (.java with annotations) with ajc and I wanted to have that integrated into the Maven build process. I tried several means, finally finding the one that worked.

Note: I had to use ajc even though I was using the pure java 5 syntax based on annotations instead of the legacy AspectJ syntax due to bug in AspectJ (fixed in v. 1.6.6).

Failed Attempts

aspectj-maven-plugin v1.2

First I tried the AspectJ Maven plugin but it didn't work for me because I had a special need - a project containing only an aspect while the plugin requires, if I remember correctly, also the advised sources to be in the project. A fix is available and should be included in the version 1.3 but the project doesn't seem to be very active so who knows when it will be released. See MASPECTJ-7.

maven-compiler-plugin for aspectj

Next I tried the maven-compiler-plugin, which supports various back-ends including AspectJ with the dependency on plexus-compiler-aspectj and compilerId set to aspectj. Unfortunately the plexus-compiler-aspectj is quite out of date, supporting only AspectJ 1.3 while I needed 1.6.

Finally the Success: maven-antrun-plugin

Being failed by Maven plugins, I had to resort to the standard way of running ajc via Ant. Fortunately Maven has a very good integration of Ant and its tasks.

The only problem here was that Ant requires ${java.home} to point to JDK (and not JRE) to find javac. It doesn't help to set the envrionmental variable JAVA_HOME to point to the JDK because Maven resets it to $JAVA_HOME/jre in the case - see MANTRUN-91. The solution is to add tools.jar (which includes javac classes) to maven-antrun-plugin's dependencies.

The corresponding piece of pom.xml:
<build>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <!-- Tell javac not to compile sources for antrun will do it -->
    <configuration>
        <excludes>
            <exclude>**/*.*</exclude>
        </excludes>
    </configuration>
  </plugin>

<plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.3</version> <dependencies> <dependency> <groupId>sun.jdk</groupId> <artifactId>tools</artifactId> <version>1.5.0</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <!-- apectj ant plugin --> <version>1.6.0</version> </dependency> </dependencies>

<executions> <execution> <phase>compile</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <echo>AntRun: Compiling AspectJ classes with ajc, java.home=${java.home}</echo> <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties" classpathref="maven.plugin.classpath" />

<iajc srcDir="src/main/java" destDir="target/classes" verbose="true" showWeaveInfo="true" source="1.5" classpathRef="maven.compile.classpath" Xlint="ignore" >

<exclude name="eu/ibacz/pbns/util/aspect/ExampleTimingAnnotatedAspect.java"/> </iajc>

</tasks> </configuration> </execution> </executions> </plugin> </plugins> </build>
Note: maven-antrun-plugin v1.3 uses Ant 1.7.1 - see http://maven.apache.org/plugins/maven-antrun-plugin/dependencies.html

Conclusion

It's a bit tricky but very well possible to run AspectJ compiler instead of javac during a maven build. The most flexible way is to use the AspectJ Ant task and maven-antrun-plugin though in more standard cases the aspectj-maven-plugin can serve you well too.