Intercepting MongoDB calls using AspectJ in a Spring project - spring

I am using Spring and the MongoDB java driver and I am trying to intercept all calls on the mongo DBCursor object to view queries before they get executed.
I've been trying to do this using the aspject-maven-plugin for external jars.
http://mojo.codehaus.org/aspectj-maven-plugin/weaveJars.html
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<verbose>true</verbose>
<privateScope>true</privateScope>
<complianceLevel>1.5</complianceLevel>
<weaveDependencies>
<weaveDependency>
<groupId>org.mongodb</groupId>
<artifactId>>mongo-java-driver</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
I am already using Spring AOP and have aspecj configured in java code
#EnableAspectJAutoProxy
I am then adding the following to a class which uses the #Aspect annotation. (Other intercepts are working fine on custom classes which are in the source code of my project)
#Pointcut("execution(* com.mongodb.DBCursor..*.*(..))")
public void interceptAndLog(ProceedingJoinPoint invocation){
_loggingService.Info("intercepted DBCursor");
}
I have also tried replacing #Pointcut with #Before but neither work.
Thanks in advance,
Ronan

Related

Mapstruct - cannot find symbol [Kotlin + Maven]

I'm having the following error when I run the command mvn clean install:
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/target/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/DataMapperImpl.java:[10,40] cannot find symbol
[ERROR] symbol: class DataMapperDecorator
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/target/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/DataMapperImpl.java:[10,74] cannot find symbol
[ERROR] symbol: class DataMapper
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/xxx/generated-sources/kapt/compile/com/xxx/xxx/xxx/api/DataMapperImpl.java:[12,19] cannot find symbol
[ERROR] symbol: class DataMapper
[ERROR] location: class com.xxx.xxx.xxx.xxx.DataMapperImpl
It seems that after mapstruct has generated the DataMapperImpl.java class it is not able to find the classes DataMapper and DataMapperDecoretor.
The code related to mapstruct is in a xxx.kt file:
//Other stuff
...
#Mapper
#DecoratedWith(DataMapperDecorator::class)
interface DataMapper {
#Mappings(
Mapping(source = "data.value", target = "dataValue"),
Mapping(source = "data.current.value", target = "currentValue"),
)
fun toDto(data: Data) : RefDataDto
}
abstract class DataMapperDecorator : DataMapper {
#Autowired
private val delegate: DataMapper? = null
override fun toDto(data: Data): dataDto {
val dataDto = delegate!!.toDto(data)
dataDto.primaryValue = data.primaryValue?.let { CurrencyUtil.toMajor(it) }
return dataDto
}
}
Regarding the pom files I have in the root file:
...
<properties>
...
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
...
and this is the pom of the module where I'm using mapstruct:
...
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
...
I hid some part of the files with dots and I'm not using the project Lombok (I saw same problems related with it we you are trying to use these projects together).
UPDATE 1:
I noticed that the error is related to the fact that from the generated class DataMapperImpl.java the package where there are the classes that this generated class should use is not visible. Indeed I see this error:
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/xxx/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/RefDataMapperImpl.java:[3,47] package com.my.package.application.domain does not exist
and of course this package exist!
UPDATE 2:
I'm continuing to investigate on this issue. I tried to make it simpler deleting the DataMapperDecorator and put the DataMapper, the Data and the DataDto class in the same file. Still the same error cannot find symbol: class for all the three classes. I'm not sure if this is related to the fact that in the DataMapperImpl (the generated class) doesn't have the import of these classes. There are imports just for the standard java libraries such as:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import javax.annotation.processing.Generated;
EDIT 1:
From the log I can also see the following warning:
[WARNING] 'tools.jar' was not found, kapt may work unreliably
UPDATE 3:
Without mapstruct under target->classes (using IntelliJ IDEA) I can see the classes of my project. On the other hand when I have introduced mapstruct what I'm seeing is that the mapstruct classes are generated under target->generated-sources->kapt->compile but under target->classes I don't see the other classes. Could the mapstruct classes be generated earlier than the other classes of my project causing the compiler to not find the Data, DataDto classes?
SOLVED!
The problem was due to the order of the compilation. By default the java compiler is executed before the kotlin compiler. That why the code generated by mapstruct wasn't able to find the kotlin classes. So it is needed to compiler the koltin classes before and then the java classes.
"The idea is to disable default compile execution and introduce our own to get control over the order in which goals are executed, so that we could run kotlin compiler before java compiler."
https://discuss.kotlinlang.org/t/maven-compiler-plugin-question/5260/4
So the solution came introducing the maven plugin:
https://kotlinlang.org/docs/maven.html#compile-kotlin-and-java-sources
So I added this to my pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
I am not sure how Kotlin works with multiple classes in one source file.
What I would suggest is that you use dedicated files for the decorator and the mapper. That way MapStruct will create the correct code.
MapStruct is a Java annotation processor, we do not know anything about the Kotlin structure. It seems like the packages returned by the java annotation processing API are not correct.
Addition to #SGiux answer. The order of plugins in pom also matters:
kotlin-maven-plugin
maven-compiler-plugin

Spring Boot Admin - info.version

We have a service which uses a custom context path. In order to correctly register our Service on Eureka Server, we've set the following:
eureka.instance.statusPageUrl=http://xxx/custom/info
eureka.instance.healthCheckUrl=http://xxx/custom/health
eureka.instance.homePageUrl=http://xxx/custom/
This is working well, our application gets registered. However, although we have set the info.version information, it doesn't get displayed on the Spring Boot Admin homepage. For our application where we don't have a custom context path, it's working:
Any idea which property(ies) is/are eventually missing?
You need to add the following into your pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Documentation link

Entity mapping to DTO with DI with MapStruct

I am new in mapstruct and I am using spring as DI I follow up MapStruct documentation page regarding DI containers section 4.2 I tried to map my entity to dto as below :
#Mapper(componentModel = "spring")
public interface CustomerMapper {
#Mapping(source = "registered",target = "activeProfile")
CustomerDto customerToCustomerDto(Customer customer);
}
when i run mvn install i got this error :
java:27: error: No property named "registered" exists in source parameter(s).
#Mapping(source = "registered",target = "activeProfile")
my entity using lombok and I am sure there is registered field
please help
You don't have to to remove Lombok.
You can setup it to work before MapStruct as was described here by ahus1
https://github.com/mapstruct/mapstruct/issues/510
<!-- first de-lombok the sources to make getters/setters visible for mapstruct,
but *DON'T'* add the output directory to the sources, as we will only need it for mapstruct processing -->
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>${org.projectlombok.maven.version}</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
<configuration>
<sourceDirectory>src/main/java</sourceDirectory>
<addOutputDirectory>false</addOutputDirectory>
<outputDirectory>${project.build.directory}/delombok</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- use the de-lomobok files to create the necessary mappers -->
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.2.4</version>
<configuration>
<defaultOutputDirectory>
${project.build.directory}/generated-sources/mapstruct
</defaultOutputDirectory>
<processors>
<processor>org.mapstruct.ap.MappingProcessor</processor>
</processors>
<sourceDirectory>
${project.build.directory}/delombok
</sourceDirectory>
</configuration>
<executions>
<execution>
<id>process</id>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- now take the original sources together with the created mappers to the compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<annotationProcessors>
<annotationProcessor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
I've solved the problem using annotationProcessors in pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
I removed lombok from Entity and created setters /getters manually and worked well
Neither you have to remove lombok from your project nor you have to mess up the maven compiler plugin. You just have to declare the lombok dependency before you declare the mapstruck dependency in your pom. With this order maven is able to de-lombok your classes, before mapstruct referes to the getters and setters. This is possibly a feature of maven's dependency mediation.
Dependency mediation - this determines what version of a dependency
will be used when multiple versions of an artifact are encountered.
Currently, Maven 2.0 only supports using the "nearest definition"
which means that it will use the version of the closest dependency to
your project in the tree of dependencies. You can always guarantee a
version by declaring it explicitly in your project's POM. Note that if
two dependency versions are at the same depth in the dependency tree,
until Maven 2.0.8 it was not defined which one would win, but since
Maven 2.0.9 it's the order in the declaration that counts: the first
declaration wins.
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies
The issue is, that Lombok generated properties are not visible to JSR-269 annotation processors. It uses internal api to modify the source elements directly instead of generating new artifacts from the annotated source files Therefore any annotation processor that relies on existence of getter/setter methods will not see them in the source code when it gets executed. Javac will pass the ,,original" source code to the annotation processor(in our case Mapstruct) without any modifications done by Lombok.
Right now the most clean solution how to get both of them working side-by-side is to move the Lombok annotated types and mappers into 2 separate projects. See an official example in Mapstruct repo.

Binding a custom Maven plugin to a default phase

I have a custom Maven plugin that I'm trying to bind to the package phase by default. I've tried every combination of using the #Mojo annotation along with the #Execute annotation, but it doesn't seem to auto bind.
The only way I manage to get my plugin to work is by defining it like this:
#Mojo(name = "put")
public class SSHMojo extends AbstractMojo {
And then in my project using the plugin, defining an execution. I'd like to avoid having to add the <executions> every time I want to use my plugin.
<plugin>
<groupId>com.patrickgrimard</groupId>
<artifactId>ssh-maven-plugin</artifactId>
<version>1.0.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>put</goal>
</goals>
</execution>
</executions>
<configuration>
<serverId>devopsmtl</serverId>
<host>example.com</host>
<remoteDirectory>/srv/www</remoteDirectory>
</configuration>
</plugin>
My full plugin pom can be found at https://github.com/pgrimard/ssh-maven-plugin/blob/master/pom.xml
Hi simply use the following:
#Mojo( name = "put", defaultPhase = LifecyclePhase.PACKAGE )
Apart from that i would suggest to use a newer version of maven-plugin-api (3.0 at least)...
Use annotation attribute defaultPhase (like already mentioned by khmarbaise):
#Mojo(name = "put", defaultPhase = LifecyclePhase.PACKAGE)
public class SSHMojo extends AbstractMojo { ... }
In the pom.xml of the consuming Maven project you can leave away the reference to the phase after this:
<plugin>
<groupId>com.patrickgrimard</groupId>
<artifactId>ssh-maven-plugin</artifactId>
<version>1.0.2</version>
<executions>
<execution>
<!-- <phase>package</phase> --><!-- needed no longer -->
<goals>
<goal>put</goal>
</goals>
</execution>
</executions>
...

Maven failsafe plugin will not run test classes annotated with JUnit Category

I have an interface like this:
public interface IntegrationTest {
}
I configure the failsafe plugin like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.14</version>
<configuration>
<groups>acme.test.IntegrationTest</groups>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
If I then create an integration test like this
#Category(IntegrationTest.class)
public class ExampleClassIntegrationTest {
#Test
public void slow_and_painful_test() {
This test will not run.
If I however name the class according to the Inclusions and Exclusions of Tests
**/IT*.java
**/*IT.java
**/*ITCase.java
Like so:
#Category(IntegrationTest.class)
public class ExampleClassIT {
#Test
public void slow_and_painful_test() {
The test runs fine. Why do I have to name the test AND have an annotation when i use the groups-tag? Am I missing something? The documentation on using JUnit states that you can use the Category annotation at the class level.
Thats because these are the default java classes which fail safe plugin includes when executed.
You can however over ride this in your pom with tag :
E.g
<includes>
<include>**/*.java</include>
</includes>
To include all the java files.
You should either add JUnit as a dependency (>4.8) which is already done or in particular add the following to your failsafe-plugin configuration:
<plugins>
[...]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.14.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
</plugin>
[...]
</plugins>
But i assume it will not change the situation.

Resources