Maven annotation processing with maven-compiler-plugin - maven-2

I try to compile my code that contains annotations that generate source code. I use the maven-compiler-plugin and build-helper-maven-plugin. My POM is looking like that:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<generatedSourcesDirectory>${project.build.directory}/generated-sources/apt</generatedSourcesDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/apt</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
When I run mvn compile, ${project.build.directory}/generated-sources/apt is added as a source directory, and the generated sources are generated in the correct directory. But I get compiler errors because of missing references to the generated classes. It's like the generated source directory is not included in the compilation process.
I also try apt-maven-plugin which does not generate anything. And maven-annotation-plugin but it behaves as describe above.

The release 2.0.7-SNAPSHOT of maven-annotation-plugin should solve the problem

fwiw I just downgraded from 3.0 to 2.5.1 and fixed an issue I was seeing with APT processing not being executed after a few runs, using maven so just downgraded one version:
http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.apache.maven.plugins%22%20AND%20a%3A%22maven-compiler-plugin%22

Can you try with the latest version of maven compiler plugin (2.3.2)?
Also build-helper-maven-plugin is not required since it looks like you are using the maven-compiler-plugin itself to generate the sources from the annotation.

Related

Compiling gRPC,with both Kotlin and Java using Maven (various packages not found)

I have a mixed kotlin/java project and I wanted to add gRPC to it. I configured the gRPC plugin as usual:
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>
com.google.protobuf:protoc:3.11.2:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>
io.grpc:protoc-gen-grpc-java:1.25.0:exe:${os.detected.classifier}
</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
...
but when building from scratch
mvn clean && mvn package
the kotlin code would never find the generated sources. When building first from IntelliJ it would work fine - IntelliJ knows what to do.
I tried configuring build-helper-maven-plugin to include the generated-sources directories that the protobuf compiler and stub generator use, but that didn't seem to have any effect (and in fact seems unnecessary).
The answer it turns out is because of the order plugins execute. Generally for kotlin-java hybrid projects you want to compile the kotlin first so that the java compiler knows how to find kotlin classes. The problem is, if you do that the kotlin compiler doesn't see the protoc-generated java classes yet. It's a circular dependency.
It took me a while to figure it out, but to fix it you just have to tell the kotlin compiler where to find the protoc-generated sources like this:
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
<sourceDir>${project.build.directory}/generated-sources/protobuf/java/</sourceDir>
<sourceDir>${project.build.directory}/generated-sources/protobuf/grpc-java/</sourceDir>
</sourceDirs>
</configuration>
</execution>
...
</plugin>
It took me entirely too long to figure that out, so I'm posting this as a self-answered question to perhaps save somebody else some time.
I saw a number of related questions but none exactly the same. Good luck.

Disable the default-jar execution

I am using Maven Assembly plugin to pack a jar file.
But when I run mvn package, maven always trigger the [jar:jar {execution: default-jar}] to create a default jar file.
So I will have 2 jar files (one created by Assembly plugin and one created by Maven jar which i don't want to be created).
How can I turn off the default-jar execution?
In my pom.xml, I am using: <packaging>jar</packaging>.
I don't want to change it to <packaging>pom</packaging>.
(...) So i will have 2 jar files (one created by assembly plugin and one created by maven jar which i dont want to be created).
Looks like you're doing pretty complicated things. Maybe Maven is not the right tool in your case.
How can I turn off the execution: default-jar.
You can set the <phase> of the corresponding execution to something unknown, like none:
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>default-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- this is used for inheritance merges -->
<phase>package</phase>
<!-- append to the packaging phase. -->
<goals>
<goal>single</goal>
<!-- goals == mojos -->
</goals>
</execution>
</executions>
</plugin>
This seems to work as long as you're providing something else to be installed, like an assembly (I only tested install). But of course, this is a hack.
While not a direct answer to the question, you could exclude the jar created by maven jar using <useProjectArtifact>false</useProjectArtifact>

Maven: How can my mojo access its own resources?

I have a project (here called my-artifact) which needs to generate sources from a model file. I've created a maven-plugin (my-code-generator) which is used as described in the pom.xml excerpt below. It loads and processes the model.xml from my-artifact's resources and generates code using some predefined templates stored within the plugin. The question is how my-code-generator could access these templates as they are not in the project resources but within its own resources.
Thanks in advance
<plugin>
<groupId>my-group</groupId>
<artifactId>my-code-generator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<configuration>
<modelfile>
src/main/resources/model.xml
</modelDir>
</configuration>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-model</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
<sources>
<source>target/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
Just use the ClassLoader, to get resources from the MyCodeGenerator Maven plugin.
Add something like this to your MyCodeGeneratorMojo
URL getTemplate(String fileName) {
return this.getClass().getResource(fileName);
}
Within the MyCodeGenerator Maven plugin, add the template(s) to the src/main/resources directory (don't forget to use the correct package entry (directories) within that directory).
By including them in the jar file for the plugin and referencing them via classpath, via ClassLoader.getResourceAsStream.
By packaging them as another artifact, declaring them as a dependency, and calling the dependency-resolution API, which is a lot more work.

Can I set the project version with a buildnumber-maven-plugin?

I'm trying to add the svn.revision to project version as a build number and can't seem to do so. My jar has the correct name durin packaging, but its installed in the my local repository it is as if ${buildNumber} is/was undefined when the version was set.
I get foo-1.0.0-SNAPSHOT-${buildNumber} instead of foo-1.0.0-SNAPSHOT-304
Any idea what I'm doing wrong or is adding a revision to the project version a bad idea? Thanks for the help.
<project>
...
<version>1.0.0-${release.identifier}-${buildNumber}</version>
<properties>
<release.identifier>SNAPSHOT</release.identifier>
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<executions>
<execution>
<id>useLastCommittedRevision</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<useLastCommittedRevision>true</useLastCommittedRevision>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
</project>
The problem has two parts:
You're trying to set the buildNumber into the version before it is resolved so it will always be ${buildNumber} rather than the resolved value.
Instead of trying to dynamically change the version, you should set the buildNumber into the finalName element in the build. This will create the artifacts with the intended name in the local repository.
The install plugin will ignore the finalName and deploy it as 1.0.0-SNAPSHOT regardless, I don't know of a way to address that. The buildNumber is added to the Manifest if you configure the plugin as below.
So your configuration would be something like:
<version>1.0.0-${release.identifier}</version>
...
<build>
<finalName>${project.artifactId}-${project.version}-${buildNumber}</finalName>
...
</build>
I would avoid using build numbers on SNAPSHOT projects.
Maven provides the SNAPSHOT keyword to signify a volatile project in active development. So if you reference a project with a SNAPSHOT dependency version, Maven will automatically check for updates and keep your dependencies in sync.
If you then add a build number to the end of that version, you will have to manually update the dependencies, so you lose any benefit of having the SNAPSHOT suffix.
I personally avoid using build numbers where possible anyway. If I have to update a project, I just bump the version number, or use a suffix like beta-2 or RC2. If you need to track the revision in the SNAPSHOT, I'd recommend adding it to the Manifest so you can check where the build originated, but use the standard SNAPSHOT suffix to allow Maven to resolve the versions normally. The configuration below shows how to add the revision to the Manifest.
As far as your configuration is concerned, it looks OK to me assuming your SCM url is set up correctly. If you have no SCM configuration in your POM that may be the problem.
Can you run with -X and check for any output from the plugin indicating why it isn't setting the property?
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>0.9.4</version>
<executions>
<execution>
<id>useLastCommittedRevision</id>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.1</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Implementation-Build>${buildNumber}</Implementation-Build>
</manifestEntries>
</archive>
</configuration>
</plugin>
Add this after the buildnumber-maven-plugin:
<plugin>
<groupId>io.github.michaldo</groupId>
<artifactId>nashorn-maven-plugin</artifactId>
<version>0.0.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>eval</goal>
</goals>
<configuration>
<script>
$project.artifact.version = "${buildNumber}";
</script>
</configuration>
</execution>
</executions>
</plugin>
And the buildNumber will be recognized by packaging and deploy.

How to run individual test in the integration-test target in maven

We have a hundreds of tests defined for our integration-test phase lifecycle in maven, and they take a long time to finish.
What I want to do is run just one test in the integration-test. I tried doing :
mvn -Dtest=<my-test> integration-test
but that does not work. The -Dtest runs only the tests in the unit test goal, not the integration-test phase. I tried the -Dintegration-test=<my-test> instead, and that was ignored.
Is there a way to do that ?
My configuration is:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/api/**</include>
</includes>
.....
If you're using the Maven failsafe plugin, you can run a single integration test by setting the it.test property to your fully qualified test class name:
mvn -D it.test=your.TestCase verify
See the failsafe plugin docs for more info.
The Failsafe documentation would have you specify the test like so:
mvn -Dit.test=BrokenIT verify
However, -Dit.test does not appear to work any longer. Rather, the same parameter used to specify a Surefire test will apparently work for Failsafe as well. For example:
mvn -Dtest=WorksIT verify
I've filed a bug (EDIT: which was closed as "Cannot Reproduce" in 2.12) to correct the documentation.
just add -DfailIfNoTests=false works for me with testNG. Something like this:
mvn integration-test -Dtest=aITest -DfailIfNoTests=false
I struggled through this, and I created an additional profile to use when I wanted to run just one integration test. I hope that I've successfully extracted just the right part here:
<profile>
<id>integrationTestSingle</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<includes>
<include>**/integration/**/${test}.java</include>
</includes>
<skipTests>false</skipTests>
</configuration>
</execution>
</executions>
<configuration>
<argLine>-Xms256M -Xmx768M -XX:MaxPermSize=256M</argLine>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>default-test</id>
<configuration>
<skipTests>true</skipTests>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Now, I call maven with the integrationTestSingle profile and with -DfailIfNoTests=false -Dtest=NameOfTest, and it doesn't run any of the regular tests during the regular "test" phase, and runs just the NameOfTest test during the integration-test phase.
I'm not sure about JUnit, but for TestNG the strategy would be to define a suite XML file with only the one test, and then in your POM configure the surefire plugin to only run that. In your POM, you would have something like this (disclaimer, this is untested):
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>single-test.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
To configure the suite file, see http://testng.org/doc/documentation-main.html
Just ran into this myself. Something like this worked well for me:
mvn -Pintegration-test -Dtest=<my-test>
The trick was to ensure that the test-group was mentioned before the -Dtest portion.
I am using:
Apache Maven 3.6.3
openjdk version "11.0.2" 2019-01-15
<groupId>org.codehaus.mojo</groupId>
<artifactId>failsafe-maven-plugin</artifactId>
<version>2.4.3-alpha-1</version>
This command worked for me:
mvn failsafe:integration-test -Dsurefire.skip=true -DskipIntegrationTests=false -DskipTests=false -Dtest=com.myxyz.func.ITestGate
Was actually simpler that the answers above by going back to basics with the actual documentation.
Running Junit 5 integration tests:
openjdk version "11.0.11" 2021-04-20
Apache Maven 3.6.3
In the main build just drop in documented failsafe config:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M5</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Then you can run only a specific integration test with:
mvn -Dtest=\*cs1_\* verify
Note that this version will run your tests in the target folder and if you need to load any external files that are something like src\test\resources\x.y then they are copied to target\test-classes\x.y
This works for me, when I gonna run only one test method in integration test
mvn clean -Dit.test=some.package.SomeTestClass#testMethodName integration-test