<project xmlns=[...]>
[...]
<profiles>
<profile>
<id>dev-env</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.2a</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>dev-prod</id>
<activation>
<property>
<name>env</name>
<value>prod</value>
</property>
</activation>
</profile>
</profiles>
</project>
You'll notice the use of Maven profiles to distinguish between development and production environments: the focus of this post being on contract enforcement at development time, I wanted to handle the case where AspectJ would only be used for that purpose; we might want to weave the compile-time aspects only during development, and not leak the aspectjrt dependency to the production environment (for instance, this might be an already existing project and our customer might not want to add a new dependency).
Of course, if AspectJ is used for anything else than these compile-time checks, profiles are not necessary: the <dependency> and <build> tags can be added directly under the <project> element, and the aspects will be compiled and weaved in any case.
Going back to project aop-test, we can now try the two profiles:
- launching mvn clean compile -Denv=prod triggers the prod-env profile, which bypasses the compile-time checks;
- launching mvn clean compile triggers the default dev-env profile and compile-time checks are activated. The error is raised and the message even points us to the corresponding aspect:
[INFO] [aspectj:compile {execution: default}]
[ERROR] substring can only be called from package com.acme.util
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Compiler errors :
error at myPostalCode.substring(0, 2);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
D:\projects\tests\src\aop-test\src\main\java\com\acme\business\ExampleBusiness.j
ava:19:0::0 substring can only be called from package com.acme.util
see also: D:\projects\tests\src\aop-test\src\main\aspect\com\acme\aspect
s\CompileChecks.aj:21::0
However, I ran into a strange bug: running mvn compile a second time does not invoke the AspectJ compiler, and the project compiles without any error!
Running Maven with the -X option, I noticed the following message: [DEBUG] No modifications found skipping aspectJ compile. I localized it in the online sources of the Maven plugin: at line 459 of AbstractAjcCompiler.java, we can see in the isBuildNeeded() method that the AspectJ compiler is only invoked when one of the following conditions is met:
- we are running a new build from a clean project;
- the AspectJ configuration has changed since the last build (it is stored in target/classes/builddef.lst);
- the project sources have changed.
- running mvn clean compile each and every time;
- adding a snippet of ANT code in the POM to manually delete builddef.lst;
- filing a bug with the aspectj-maven-plugin team, to request a switch to bypass the isBuildNeeded() method.
0 comments:
Post a Comment