Search code examples
javaintellij-ideaaspectjlombokaspectj-maven-plugin

How to use AspectJ + Lombok + Maven + IntelliJ?


<plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.10</version>
                <configuration>
                    <verbose>true</verbose>
                    <showWeaveInfo>true</showWeaveInfo>
                    <source>1.8</source>
                    <target>1.8</target>
                    <complianceLevel>1.8</complianceLevel>
                    <verbose>false</verbose>
                    <Xlint>ignore</Xlint>
                    <outxml>true</outxml>
                    <forceAjcCompile>true</forceAjcCompile>
                    <reweavable>false</reweavable>
                    <!-- this is important: start-->
                    <sources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/classes</weaveDirectory>
                    </weaveDirectories>
                    <!-- this is important: end-->
                </configuration>
                <executions>
                    <execution>
                        <!-- The right phase is very important! Compile and weave aspects after all classes compiled by javac -->
                        <phase>process-classes</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>1.8.9</version>
                    </dependency>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>1.8.9</version>
                    </dependency>
                </dependencies>
            </plugin>

According to the standard, the aspectj-maven-plugin provides weaving during compilation. But Lombok is a compile-time preprocessor. Therefore, in order for the weaving to occur after the code is compiled, the following is necessary.

In the plugin:

<forceAjcCompile>true</forceAjcCompile> и <sources/>

You also need to turn off the autobuild in Intellij Idea. And execute the following command:

mvn clean compile install -Pdev

Only as a result of this command, the necessary weaving begins! Because of the "install" command.

Tell me, please, why is the weaving happening only thanks to this command? Or are other command options possible, for example, so that tests are not pulled up, etc.?


Solution

  • 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 use inter-type declarations
    • post-compile time - we compile sources using javac and after that ajc 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:

    enter image description here