I have a project that uses compiled aspects and weaves them at compile time. I want to add Lombok, but unfortunately AJC is not supported by Lombok. Since this project doesn't have any sources of aspects on its own i configured AspectJ Maven plugin to do post-compile weaving instead, after compiling with Javac+Lombok.
Here is config for AspectJ Maven plugin:
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectory>${project.build.outputDirectory}</weaveDirectory>
It's attached to compile phase right after Maven Compiler plugin compile. That way Lombok + Javac will be invoked first and later AJC will perform weaving on Javac's generated class files.
Is there any limitations/disadvantages when performing bytecode weaving on javac generated classes?
Maybe there is a better approach of making Maven+Lombok+Aspects+Idea work together without issues.
Here is a minimal example project: https://github.com/Psimage/aspectj-and-lombok
When in the other question you asked me in a comment I actually thought that you had problems with your approach, but it is working. The only thing I had to do in order to run the test directly from IDE (IntelliJ IDEA) is to actually delegate application and test runners to Maven because otherwise IDEA does not get Lombok + AspectJ applied at the same time.
If your approach works, use it. But actually AspectJ Maven suggests another approach: compiling with Maven compiler first to another output directory, then use that directory as weave directory for the AspectJ compiler. The sample POM there does not work 100%, though, because when specifying an output directory for Javac on the command line that directory needs to exist, it will not be created by the compiler. So you need some ugly Antrun action, too:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>unwovenClassesFolder</id>
<phase>generate-resources</phase>
<configuration>
<tasks>
<delete dir="${project.build.directory}/unwoven-classes"/>
<mkdir dir="${project.build.directory}/unwoven-classes"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<!-- Modifying output directory of default compile because non-weaved classes must be stored
in separate folder to not confuse ajc by reweaving already woven classes (which leads to
to ajc error message like "bad weaverState.Kind: -115") -->
<id>default-compile</id>
<configuration>
<compilerArgs>
<arg>-d</arg>
<arg>${project.build.directory}/unwoven-classes</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>me.yarosbug</groupId>
<artifactId>aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/unwoven-classes</weaveDirectory>
</weaveDirectories>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
I would suggest another approach as an alternative:
The advantage is that you don't need to fiddle around with multiple compilers, execution phases, output directories, Antrun etc.
Update:
I cloned your GitHub MCVE and this commit on branch master reflects what I have explained in my sample XML above.
I also created a branch multi-phase-compilation with another commit which effectively refactors the project according to my alternative idea. I am just quoting the commit message:
Multi-phase compilation: 1. Java + Lombok, 2. AspectJ binary weaving
There are many changes (sorry, I should have split them into multiple
commits):
- Marker annotation renamed to @marker and moved to separate module
because the main application should not depend on the aspect module.
Rather both application and aspect now depend on a common module.
- New module "main-app-aspectj" does only AspectJ binary weaving on
the already lomboked Java application.
- Both application modules have slightly different unit tests now: One
checks that Lombok has been applied and AspectJ has not, the other
checks that both have been applied.
- Aspect pointcut limits matching to "execution(* *(..))" in order to
avoid also matching "call()" joinpoints.
The end result is that now we have a clear separation of concerns, clear
dependencies, no more scripted Ant build components and the new option
to use the lomboked code optionally with or without aspects applied
because both types or JARs are created during the build.
Feel free to add my fork as another remote to your Git repository and pull in my changes from there. If you prefer me to send you pull requests in order to make it easier, just let me know.
Update 2, 2023-12-16:
I revisited this topic for another reason and realised, that last time I did not mention one important thing: In a multi-module approach with an intermediary, unwoven and a final, woven module, the former should be declared with provided
scope in the latter, because we want to avoid the unwoven module ending up on the classpath of other modules depending on the woven one. This is important, because otherwise two sets of (duplicate, but different) classes would end up on the classpath, and depending on the exact classl-loading situation, either one could be found first.
Therefore, I added a few commits to the multi-module branch, cleaning up the situation and adding a dependent module with a test on classpath content to make sure everything works as expected.