Binding a custom Maven plugin to a default phase - maven

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>
...

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

Maven exec plugin Class Not Found Exception

when I right click on the class that has the main() method in Eclipse, and go into properties -> resource, the path to the class is this:
/UserRegistrationServices/src/main/java/main/Application.java
In my POM.xml file I have this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>my-execution</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>UserRegistrationServices.src.main.java.main.Application.java</mainClass>
</configuration>
</plugin>
But for some reason maven cannot find the class.
Help would be appreciated, thanks.
The <mainClass> element takes a fully qualified class name. The fully qualified name of a class consists of the package and the actual name of class. In a default Maven project, the package name is relative to src/main/java. That means, the package of your Application class is main. You can verify that by looking at the package declaration in the class itself.
Therefore the <mainClass> value needs to be main.Application.

Maven: custom assembly deployment

Due to need for heavy customization I did developed my own Groovy plugin, which creates ZIP archive, which is 100% ready for deployment (like Maven assembly plugin does). Still, if I run
mvn clean install ...
command it creates an assembly (single ZIP file), puts it to ${project.build.directory} (.../target) and that's it.
How do I tell Maven, that it's now part of deployment and I would like to deploy this ZIP file?
You have two options:
Use buildhelper:attach-artifact:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>some file</file>
<type>extension of your file </type>
<classifier>optional</classifier>
</artifact>
...
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
Alternatively (and better), you could include the necessary code in your own plugin:
#Component
protected MavenProject project;
#Component
protected MavenProjectHelper projectHelper;
...
projectHelper.attachArtifact(project, "jar", resource.getClassifier(), targetArchive);
Actually it worked in Groovy too (running from groovy-maven-plugin):
def helper =
session.lookup("org.apache.maven.project.MavenProjectHelper");
helper.attachArtifact(project, "zip", _classifier, new File(_archiveFilename));
N.B.:
Both _classifier and _archiveFilename should be declared and initialized by your code.

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.

Intercepting MongoDB calls using AspectJ in a Spring project

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

Resources