Aspectj with Lombok - java

There are two different projects in which we need to use AspectJ.
Plugin in pom.xml:
<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>
<!-- <encoding>UTF-8</encoding> -->
<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>*
Dependencies:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
Exception:
Caused by: org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException: Pointcut expression 'handler(*) && args(e)' contains unsupported pointcut primitive 'handler'
The first project does not contain a Lombok, so the "Build Project" or "Rebuild Project" helps in this situation. But there is weaving during compilation, and everything works out correctly.
But the second project uses Lombok, and the solution with "Build/Rebuild" does not help, because build means weaving at compile time and => AspectJ does not see the functionality of Lombok (For example, getters).
At the same time, a setting has been introduced in the plugin so that weaving works on the spot, and not during compilation: <forceAjcCompile>true</forceAjcCompile> and empty <sources/>.
The combination of AspectJ and Lombok is mentioned in the news documents for frequently asked questions on Lambda power tools:
https://awslabs.github.io/aws-lambda-powertools-java/FAQs/
Poweretools uses aspectj-maven-plugin to compile-time weave (CTW) aspects into the project. In case you want to use Lombok or other compile-time preprocessor for your project, it is required to change aspectj-maven-plugin configuration to enable in-place weaving feature. Otherwise the plugin will ignore changes introduced by Lombok and will use .java files as a source.
To enable in-place weaving feature you need to use following aspectj-maven-plugin configuration:
<configuration>
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
...
<aspectLibraries>
<aspectLibrary>
<groupId>software.amazon.lambda</groupId>
<artifactId>powertools-logging</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
A source with the same information, the comments helped a lot:
https://palesz.wordpress.com/2011/12/03/howto-maven-lombok-and-aspectj-together/
The key of the solution is the empty sources tag in the configuration and the forceAjcCompile=true setting.
Please tell me why only "Build" (i.e. weaving during compilation) can help solve this error? What is missing (what is there when starting "build") to start weaving in place? How is it possible to resolve this situation?

The UnsupportedPointcutPrimitiveException message tells you that you seem to be mixing native AspectJ aspects with Spring AOP ones, or maybe you forgot to configure Spring in a way that makes it stop from trying to wire AspectJ aspects redundantly as Spring AOP ones again.
How can I know that without having seen your aspect code or Spring config? Because native AspectJ knows handler() pointcuts, but Spring AOP does not. So it must be Spring picking it up while wiring the application. This problem is completely unrelated to Lombok.
As you might have noticed, I cannot answer more precisely, because your question is so generic and is specifically lacking a sample project or any code, for that matter. If you would please be so kind to post an MCVE on GitHub, I can help you fix your project, in case my general explanation what went wrong is not comprehensive enough for you.

Related

Maven exclude/remove test dependency defined in parent POM

This is similar to Exclude dependency in child pom inherited from parent pom, except that it has to do with test vs compile scopes.
I have a parent POM that includes the org.slf4j:slf4j-api dependency so that all descendant projects will be using SLF4J for the logging API. Then, so that all projects can have some logging for unit tests (regardless of which SLF4J implementation they use in the main, that is non-test, part of the project), I include SLF4J Simple, but only in the test scope:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
(I understand the view that parent POMs should not declare dependencies and only use dependency management. While I don't disagree in general, configuring tests is a different story. I don't want every single subproject to have to declare JUnit, Hamcrest, Hamcrest Optional, Mockito, Simple Logging, etc. The testing framework should be uniform across all our projects without a huge amount of ceremony just to set up a project.)
This works fine until one project Foo wants to use Logback as the SLF4J implementation.
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.1</version>
</dependency>
That works fine for the Foo application itself, but now for the Foo tests, there are suddenly two competing SLF4J implementations: Logback and SLF4J simple. This presents a bindings conflict:
SLF4J: Class path contains multiple SLF4J providers.
SLF4J: Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider#363ee3a2]
SLF4J: Found provider [org.slf4j.simple.SimpleServiceProvider#4690b489]
SLF4J: See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual provider is of type [ch.qos.logback.classic.spi.LogbackServiceProvider#363ee3a2]
I need to do one of the following:
In the POM where I bring in the ch.qos.logback:logback-classic dependency, I need to exclude the org.slf4j:slf4j-simple from the parent POM. (This is the preferred solution.)
In the POM where I bring in the ch.qos.logback:logback-classic dependency, I need to specify that ch.qos.logback:logback-classic is for all scopes except the test scope (so as not to conflict with org.slf4j:slf4j-simple).
I don't readily see how to do either of these. Any ideas?
One suggestion was to redeclare org.slf4j:slf4j-simple with <scope>provided</scope>. Thus pom.xml for project Foo would look like this:
…
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>provided</scope>
</dependency>
…
Unfortunately that doesn't work. SLF4J still sees two SLF4J providers on the classpath, and is showing the message seen above. A scope of provided simply keeps the dependency from being included transitively in other projects; it doesn't seem to remove it from the classpath of the current project.
It sounds like you are trying to build the Cathedral using wrong tools and instead of Cathedral you are getting pagan temple :)
technically, it is possible to override classpath/module dependencies imposed by parent pom by defining system scope, something like:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/../dummy.jar</systemPath>
</dependency>
however, I wouldn't recommend to do that
another option is to take advantage of classpathDependencyExcludes config option of surefire plugin, something like:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<classpathDependencyExcludes>org.slf4j:slf4j-simple</classpathDependencyExcludes>
</configuration>
</plugin>
If particular parent does not suit child's needs, child may adopt another parent :) There is no strict requirement that the aggregator pom must be the parent pom
the real problem is unlike modern build tools maven does not distinguish test compile and test runtime scopes, however it is possible to emulate such behaviour
<properties>
<surefire.runtime>${project.build.directory}/surefire-runtime/slf4j-simple-2.0.1.jar</surefire.runtime>
</properties>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-surefire-runtime</id>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.1</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/surefire-runtime/</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<additionalClasspathElements>${surefire.runtime}</additionalClasspathElements>
</configuration>
</plugin>
yep, too many words there, but in my opinion that is only correct configuration for test runtime dependencies, m.b. it worth to submit a corresponding PR to surefire project - I believe that needs to write about 10 LoC to avoid maven-dependency-plugin configuration and able to configure test runtime in the following way:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<additionalClasspathElements>
<additionalClasspathElement>org.slf4j:slf4j-api:2.0.1</additionalClasspathElement>
</additionalClasspathElements>
</configuration>
</plugin>

How to generate java stubs from protobuf for Java target 11 using maven?

I am trying to generate stub using protobuf.
My pom.xml has below code
<plugin>
<groupId>com.github.os72</groupId>
<artifactId>protoc-jar-maven-plugin</artifactId>
<version>3.8.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<protocVersion>3.8.0</protocVersion>
<includeStdTypes>true</includeStdTypes>
<inputDirectories>
<include>src/main/proto</include>
</inputDirectories>
<outputTargets>
<outputTarget>
<type>java</type>
</outputTarget>
<outputTarget>
<type>grpc-java</type>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0</pluginArtifact>
</outputTarget>
</outputTargets>
</configuration>
</execution>
</executions>
</plugin>
However, it generates the source files with target as Java1.8.
I am migrating my apps to Java 11, and have included the below jars in pom.xml file:
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.activation-api</artifactId>
<version>1.3.2</version>
</dependency>
However maven protoc plugin generates the files Grpc.java with annotnation javax.annotation.Generated instead of javax.annotation.api.Generated
Is there any other way for generating the java stub with target version as JDK 11.
If you follow the grpc-java documentation, it instructs you to use:
<dependency> <!-- necessary for Java 9+ -->
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
Previous versions of the examples used javax.annotation:javax.annotation-api:1.2, which does work, but it was replaced with Tomcat for licensing reasons. In your pom.xml, it seems you might have mixed up "activation" vs "annotation", which look pretty similar at a glance.
I'm not aware of a javax.annotation.api.Generated annotation. I've not seen any real evidence that javax.annotation.processing.Generated is an appropriate replacement for javax.annotation.Generated either.

Produce tree output with Surefire like the JUnit 5 console launcher

The Console Launcher that comes with JUnit Platform (from JUnit 5) produces a quite nice summary view at the end. The Maven Surefire plugin, however, has a very simple output.
Is it possible to create with Surefire output similar to what the launches creates?
My current workaround is to disable surefire and use exec-maven-plugin to manually run ConsoleLauncher:
<!-- disable surefire -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version><!-- ... --></version>
<executions>
<execution>
<id>default-test</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<!-- enable ConsoleLauncher -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version><!-- ... --></version>
<executions>
<execution>
<phase>test</phase>
<goals><goal>java</goal></goals>
<configuration>
<mainClass>org.junit.platform.console.ConsoleLauncher</mainClass>
<arguments>
<argument>--scan-class-path</argument>
<argument>${project.build.directory}/test-classes</argument>
</arguments>
<classpathScope>test</classpathScope>
</configuration>
</execution>
</executions>
</plugin>
<!-- ... -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-console-standalone</artifactId>
<version><!-- ... --></version>
<scope>test</scope>
</dependency>
I know it's an old topic, but this topic was the reason I've developed this extension 2 years ago: https://github.com/fabriciorby/maven-surefire-junit5-tree-reporter
Basically, to get your tree output, add this to your pom.xml:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<dependencies>
<dependency>
<groupId>me.fabriciorby</groupId>
<artifactId>maven-surefire-junit5-tree-reporter</artifactId>
<version>1.0.1</version>
</dependency>
</dependencies>
<configuration>
<reportFormat>plain</reportFormat>
<consoleOutputReporter>
<disable>true</disable>
</consoleOutputReporter>
<statelessTestsetInfoReporter
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporterUnicode">
</statelessTestsetInfoReporter>
</configuration>
</plugin>
And the magic happens
Currently Surefire is developig extensions 1 for embedded Surefire features, and a standalone extension supporting JUnit5 DisplayName.
One of these extensions is a console logger of testset information. Very similar output to the console in 2 might be possible to support as well then.
The extensions is a set of Java abstractions and Surefire/Failsafe plugins will contain default implementations of these abstractions. The other progressive extension implementations, with the output like in 2, would kindly require users to support Surefire project to implement the extensions in their own GitHub repositories (not in ASF). Surefire is welcome to list all third party implementations of these extensions on the ASF Maven Surefire webpage.
This way (Open-Closed DP) we believe we would provide you with certain freedom to change the behavior of plugins without reporting real Jira issues and without waiting for a new feature release.
Sure.
Feel free to open a feature request to extend the current summary output at https://issues.apache.org/jira/projects/SUREFIRE/issue and perhaps a Pull Request against https://github.com/apache/maven-surefire ;-)

Using object from other module in aspect

I have one aspect with using aspectJ as below:
public aspect TestAspect {
pointcut classicPointcut(PersistenceManagerImpl object) : execution(manager.PersistenceManagerImpl.new(..)) && target(object);
after(PersistenceManagerImpl object) : classicPointcut(object){
System.err.println(object.getClass().getSimpleName());
}
}
this aspect is in module aspect. this module is packaking as jar. PersistenceManagerImpl is in other module but i need use it in module aspect. For dependency management i use maven. But here is of course problem with cyclic reference. Exists some way how can a resolve this problem ?
----------EDIT----------
I get only this error:
java.lang.NoSuchMethodError:TestAspect.ajc$after$TestAspect$1$cc149106(Ljava/lang/Object;)V
When i move my aspect to same module, when is PersistenceManagerImpl i obtain correct solution(of course). But this is not, what i wanted.
Could you put the error result of the compiling code? You could try to put another module as dependency first then later put the dependency on the aspectj maven plugin at weaveDependency in pom.xml as follow:
....
<dependency>
<groupId>com.maventest</groupId>
<artifactId>mytest</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
....
....
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<showWeaveInfo>true</showWeaveInfo>
<complianceLevel>${maven.compiler.target}</complianceLevel>
<encoding>${project.build.sourceEncoding}</encoding>
<weaveDependencies>
<weaveDependency>
<groupId>com.maventest</groupId>
<artifactId>mytest</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
ps: You could see my question post asking the same thing here
Your aspect seems to be specific for the module in which PersistenceManagerImpl is located, so that module should be a dependency of the aspect module. On the other hand, that module depends on the aspect module because it needs it as an <aspectLibrary> in the AspectJ Maven configuration. Indeed a circular dependency, but an unnecessary one. You have two options:
Move the aspect to the application module which it is specific for because IMO it belongs there if it explicitly uses specific classes from there. Only aspects which implement cross-cutting concerns in a way applicable to multiple modules should be in their own aspect library.
Following the previous thought, you could make your aspect more general, e.g. do something like this:
public aspect TestAspect {
pointcut classicPointcut(Object object) :
execution(*..PersistenceManagerImpl.new(..)) &&
target(object);
after(Object object) : classicPointcut(object){
System.err.println(object.getClass().getSimpleName());
}
}

Adding aspects to maven project

I created aspectJ class in seperate Maven project:
#Aspect
public class AspectE {
#Pointcut("execution(#EntryPoint * *.*(..))")
public void defineEntryPoint() {
}
#Before("defineEntryPoint()")
public void setThreadName(JoinPoint joinPoint) {
...
}
#After("defineEntryPoint()")
public void removeThreadName(JoinPoint joinPoint) {
...
}
}
Then in second project I annotated several methods and added to pom.xml:
<dependency>
<groupId>first-project</groupId>
<artifactId>first-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.0</version>
</dependency>
But still aspects aren't seen at all. Am I missing some steps? What should I do?
Did you take a look at this?
AspectJ compiler Maven Plugin - Usage
In order to weave correctly your code with your libraries, you should declare them within your dependencies AND within the aspectj weaver:
<dependencies>
<!-- Aspectj lib -->
<dependency>
<groupId>com.my.group</groupId>
<artifactId>my-aspect-lib</artifactId>
<version>1.0</version>
</dependency>
<!-- Other dependencies -->
</dependencies>
<build>
<!-- Specific build configuration -->
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>com.my.group</groupId>
<artifactId>my-aspect-lib</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
</plugin>
<!-- Other plugins configuration -->
</plugins>
</build>
<!-- Other settings -->
You have to weave the aspects with the code. This can be done in 2 ways:
Compile-time weaving, using the AspectJ compiler Maven plugin as Andrei suggested
Load-time weaving (LTW), using an agent or a custom class-loader
Load-time weaving is a bit more versatile, but can be a bit challenging to set up properly. It consumes more CPU during startup (when the weaving happens), and also has a memory footprint.
Compile-time weaving consumes more CPU during the compilation, obviously, but then you don't pay the price on each restart.
I had the same problem ... but after I added this maven repo it's working
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>

Categories

Resources