views:

647

answers:

3

What I want to do is fairly easy. Or so you would think. However, nothing is working properly.

Requirement: Using maven, compile Java 1.6 project using AspectJ compiler.

Note: Our code cannot compile with javac. That is, it fails compilation if aspects are not woven in (because we have aspects that soften exceptions).

Questions (based on failed attempts below):
*Either

  1. How do you get maven to run the aspectj:compile goal directly, without ever running compile:compile?
  2. How do you ignore the failure of compile:compile?
  3. How do you specify a custom compilerId that points to your own ajc compiler (that is make compile:compile use an aspectj compiler other than the plexus one)?*

Thanks for any and all suggestions. These are the things I've tried that have led to my problem/questions:


Attempt 1 (fail): Specify aspectJ as the compiler for the maven-compiler-plugin:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.2</version>
<configuration>
 <source>1.6</source>
 <target>1.6</target>
 <compilerId>aspectj</compilerId>
</configuration>
<dependencies>
 <dependency>
  <groupId>org.codehaus.plexus</groupId>
  <artifactId>plexus-compiler-aspectj</artifactId>
  <version>1.8</version>
 </dependency>
</dependencies>
</plugin>

This fails with the error:

org.codehaus.plexus.compiler.CompilerException: The source version was not recognized: 1.6

No matter what version of the plexus compiler I use (1.8, 1.6, 1.3, etc), this doesn't work. I actually read through the source code and found that this compiler does not like source code above Java 1.5.

Attempt 2 (fail): Use the aspectJ-maven-plugin attached to the compile and test-compile goals:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.3</version>
<configuration>
 <source>1.6</source>
 <target>1.6</target>
</configuration>
<executions>
 <execution>
  <goals>
   <goal>compile</goal>      
   <goal>test-compile</goal> 
  </goals>
 </execution>
</executions>
</plugin>

This fails when running either:

mvn clean test-compile
mvn clean compile

because it attempts to execute compile:compile before running aspectj:compile. As noted above, our code doesn't compile with javac--the aspects are required. So mvn would need to skip the compile:compile goal altogether and run only aspectj:compile.

Attempt 3 (works but unnacceptable):

Use the same configuration above but instead run:

mvn clean aspectj:compile

This works, in that it builds successfully but it's unacceptable in that we need to be able to run the compile goal and the test-compile goal directly (m2eclipse auto-build depends on those goals). Moreover, running it this way would require that we spell out every goal we want along the way (for instance, we need resources distributed and tests to be run and test resources deployed, etc)

+1  A: 

How do you specify a custom compilerId that points to your own ajc compiler (that is make compile:compile use an aspectj compiler other than the plexus one)?

I don't know how to specify another compilerId than the "official" ones. Not sure it's possible.

My understanding is that http://jira.codehaus.org/browse/MCOMPILER-107 would solve your problem (AspectJ 1.6+ does support Java 1. 6 right?). Sadly, it's still open.

How do you ignore the failure of compile:compile?

The compiler:compile goal of the Maven Compiler plugin has a failOnError optional parameter allowing to Indicate whether the build will continue even if there are compilation errors.

<project>
  ...
  <build>
    ...
    <plugins>
      ...
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <failOnError>false</failOnError>
          ...
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

This could be a ugly workaround to the above problem.

How do you get maven to run the aspectj:compile goal directly, without ever running compile:compile?

The problem is that compiler:compile is bound to the compile phase and that you can't remove a default lifecyle binding. So there is maybe another option but the only one I can think of would be to turn everything off by using a <packaging>pom<packaging> and to rebind all the goals manually (at least for these phases: process-resources, compile, process-test-resources, test-compile, test, package). Schematically, something like this:

process-resources       resources:resources
compile                 aspectj:compile
process-test-resources  resources:testResources
test-compile            compiler:testCompile
test                    surefire:test
package                 ejb:ejb or ejb3:ejb3 or jar:jar or par:par or rar:rar or war:war
install                 install:install
deploy                  deploy:deploy

That could be another ugly workaround. Disclaimer: not tested but should work.

Pascal Thivent
Yep. That is really annoying. I should be able to say "compile:compile" is replaced with "aspectJ:compile." I can *kind of* do that with the <compilerId> setting. The only problem is when I name "aspectJ" as the compilerId, it uses the plexus version which doesn't support java 1.6 instead of the aspectj plugin. I didn't know you could completely redefine phases through pom packaging! That's very good info, +1! Of course, before doing that, I'd just use solution #3 above and spell out all my goals on my eclipse run config. I'm just wondering what the so called "convention" is for solving this
gmale
Thanks so much for the extra help. I'm going to vote up that codehaus bug when I get more time today. It's sad their default aspect compiler doesn't support java 1.6 which was released over 3 years ago! Later today, I'll probably end up trying the failOnError workaround since compilation fails quickly and quietly due to softened exceptions that the javac compiler sees as unchecked. This seems to be the lesser of all the evils and possibly an "official" workaround for the codehaus/java1.6 problem.
gmale
Of course, this is only an issue when the code doesn't compile without aspects being woven in. However, that *can* happen often when using AspectJ.
gmale
@gmale Yes, I understood that. But this is a very valid use case indeed.
Pascal Thivent
A: 

I used this configuration in a project to compile AspectJ and Java 6 using Maven:

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.8</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.0.2</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.3</version>
            <configuration>
                <complianceLevel>1.6</complianceLevel>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>  
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Ref: aspectj-maven-plugin

matsev
This won't call `aspectj:compile` before `compiler:compile`
Pascal Thivent
You have complianaceLevel 1.6. That's the only thing I haven't tried but as Pascal mentioned I don't think this will fix my problem because compile:compile still happens first. I wonder if there's a way to ignore the failure of compile:compile... hmmm, I'll add that to my question above.
gmale
+1  A: 

How about telling maven-compiler-plugin to skip all *.java files and let aspectj-maven-plugin do the job ?

...
<build>
  <plugins>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.0.2</version>
      <configuration>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>aspectj-maven-plugin</artifactId>
      <version>1.3</version>
      <configuration>
        <source>1.6</source>
        <target>1.6</target>
        <encoding>utf-8</encoding>
        <complianceLevel>1.6</complianceLevel>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal>       <!-- weave main classes -->
            <goal>test-compile</goal>  <!-- weave test classes -->
          </goals>
        </execution>
       </executions>
    </plugin>
  </plugins>
</build>
Tomek
I haven't looked at this problem in a while but I think what you've written here is an excellent option that might exactly solve it.I'd have to test it to be sure that calling "mvn compile" would still invoke the aspectj compiler. Also, I'd have to check that excluding java files from the compiler plugin doesn't indirectly exclude them from the aspectJ compilation.We're currently working on another area of the project but the next time I open the middleware code, I'll test out your suggestion. Thanks! I think it's going to work.
gmale
I tried it in my maven module and it worked. Although finally resigned from excluding such this because of other reason. My project uses national characters and aspectj-maven-plugin seems to mess up with encodings.So finally I refactored module that there is no references from java to aj. Javac compiles .java and after that AspectJ compiles missing .aj files. So far working like a charm.
Tomek