How to use AspectJ Maven for binary weaving after Javac + Lombok phase
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:
- Create an unwoven Java module, doing Java + Lombok stuff there.
- Create a separate module for AspectJ binary weaving, using the Java module as a weave dependency. Because your unit test depends on both Lombok and AspectJ, put the test in this module.
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.
How to use AspectJ + Lombok + Maven + IntelliJ?
You also need to turn off the autobuild in Intellij Idea. And execute the following command:
mvn clean compile install -Pdev
the statement above is not correct from AspectJ perspective. There are three (if do not pay attention to Spring API
) modes to use AspectJ:
- compile time - when we need to compile
native aspectJ (.aj) syntax
files or useinter-type declarations
- post-compile time - we compile sources using
javac
and after thatajc
processes resulting classes - that is your case cause you have specified<sources/>
- load time weaving - that requires to either specify
-javaagent
in JVM arguments or have specialised classloader
technically, from maven lifecycle
perspective everything should work fine in case of post-compile time weaving, however IDEs typically do not trigger maven lifecycle
when you are pressing green arrow near #main
or @Test
method, instead of that IDEs try to analyse project object model (pom
) and make some assumptions about target classpath and dependencies. Unfortunately, IDEs do not support all maven plugins and that is the main reason why sometimes something does not work as expected (for example, IntelliJ do not support code generators like OpenAPI
or Axis2
, that is why we place that stuff into separate maven modules/projects and run mvn install
). It seems that purpose of your mvn ... install
is to place correct jar into .m2/repository
and give IDE a chance to pick up that jar.
UPD. Some explanations....
Let consider a case when we need to run individual unit test, from maven
perspective that would be something like:
mvn -am clean test -Dtest=TestClass#testMethod*
and maven
will launch it without facing any difficulties, because before test
step it will start compile
and test-compile
steps, where javac
and ajc
do the required job. Unfortunately, from developer perspective the maven command mentioned above "takes ages", and that is the reason why IDE tries to optimise that process by compiling only changed classes, unfortunately, if IDE does not support AspectJ (for example, IntelliJ CE does not) or does not recognise maven configuration it has no chance to produce expected output.
Your case is even more complicated because you are using lombok
, which is not compatible with ajc
(or vice versa), so to produce correct classes you need first compile sources by javac
and then postprocess output by ajc
.
If your goal is to somehow simplify IDE setup for particular project I would recommend the following:
- provide reproducible example, describe your goals and difficulties you have faced with
- try to install AspectJ plugin (if you are not on IntelliJ CE), it seems it has some useful options:
Intellij + Ajc + Lombok/Mapstruct
Enabling Post-compile weave mode
in IntelliJ solved it for me (https://www.jetbrains.com/help/idea/using-the-aspectj-ajc-compiler.html).
Related Topics
How to Disable or Bypass Hardware Graphics Acceleration(Prism) in Javafx
Log4J: How to Use Socketappender
How to Keep the Iteration Order of a List When Using Collections.Tomap() on a Stream
How to Determine If a List Is Sorted in Java
Convert a Date Format in Epoch
Rotating Bufferedimage Instances
Reserved Words as Names or Identifiers
Why Is Javac Failing on @Override Annotation
Missing Return Statement in a Non-Void Method Compiles
What Is the Purpose of Defining a Package in a Java File
Java.Util.Concurrentmodificationexception Not Thrown When Expected
Javafx Using Objects from Maincontroller or Other Controllers in Proper Controller Class
Java Web Start Support in Java 9 and Beyond
Why Is This Java Stream Operated Upon Twice
Simpledateformat Parse(String Str) Doesn't Throw an Exception When Str = 2011/12/12Aaaaaaaaa