Maven2 & Groovy compilation error but not within Eclipse - maven-2

He,
I am having a mixed Java / Groovy eclipse project.
Inside eclipse utilizing the groovy plugin everything compiles just fine. In addition I have set up my project to utilize Maven2. And still everything compiles and runs (tests) just fine within eclipse.
However, compiling the project outside eclipse, i.e. using Maven2 standalone gives me compiler errors! The project is devided into several sub-projects (parent / module). The Maven2 configuration seems to be OK cause some of the modules compile but actually one gives me an compiler error, like:
[ERROR] \Projects\X\rules\src\main\groovy\x\Normalizer.java:[18,25] normalize(java.util.List<java.util.Map<java.lang.String,java.lang.Object>>) in x.
x.util.RuleUtil cannot be applied to (java.util.List<java.util.Map<java.lang.String,?>>)
[ERROR] \Projects\X\rules\src\main\groovy\x\Statistics.java:[70,67] inconvertible types
found : capture#683 of ?
required: java.lang.String
Why is this code compiling within eclipse but not using standalone Maven2?
Thanks in advance,
/nm

The problem that you are facing is a stub generation problem. GMaven creates Java stubs for your Groovy files to compile against the remaining Java files. If your application is completely in Groovy, or there is no referencing from Java classes to Groovy classes, you can remove the <goal>generateStubs</goal> goal.
The Groovy-Eclipse compiler does not require stubs and so you are not seeing this issue inside of Eclipse.
If you do require cross referencing between Groovy and Java, I'd recommend using the groovy-eclipse-compiler plugin for maven. More information is here:
http://contraptionsforprogramming.blogspot.com/2010/09/where-are-all-my-stubs.html
With this, you will be sure that your compilation inside Eclipse and outside works exactly the same.

The Groovy Eclipse plugin uses the version of Groovy presents within the plugin folder of Eclipse (groovy-1.7.5).
Most probably, the version of Groovy referenced in your maven file is different. You can specify it thought in the gmaven-runtime:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.3</version>
<configuration>
<providerSelection>1.7</providerSelection>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.3</version>
<exclusions>
<exclusion>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<!-- <goal>generateTestStubs</goal> -->
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

Related

Is Mapstruct Java11 compatible?

I'm a bit confused. There is some documentation that says java 9 is "experimental":
https://mapstruct.org/documentation/stable/reference/html/#_using_mapstruct_on_java_9
And I found a post where a guy was having trouble in Java 10. So we are heading to java 11 and I want to know if Mapstuct will work in that environment. Specifically, will it generate the code at compile time AND does the generated code work there (I suppose the latter does).
Yes, it works on a Java 11 / Spring Boot 2 project at work, and we use Mapstruct without issues.
Yes, it is possible, although I struggled a bit with it while migrating a DropWizard project (1.3.7) to java 11. The configuration as proposed in the documentation (through the maven-compiler-plugin) didn't work for me (no error was shown, but the mapper class was not generated) so I had to use maven-processor-plugin v3.3.3.
Here is how I managed to do that:
Add the dependencies using <org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
<scope>provided</scope>
</dependency>
Then configure the plugin in the submodule as follows
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>3.3.3</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<!-- list of processors to use -->
<processor>org.mapstruct.ap.MappingProcessor</processor>
</processors>
<outputDirectory>${basedir}/target/generated-sources-mappers</outputDirectory>
<compilerArguments>-source 11 -target 11</compilerArguments>
</configuration>
</execution>
</executions>
</plugin>
The outputDirectory is something specific to our project, but I leave there to highlight the fact that the xml tag changed from version 2.x of te plugin, in case you are migrating from that.
The compilerArguments portion was required because the plugin run javac passing java version 1.6 as default argument, which won't work if you are using lambda expressions or other new features from the language.
When compiling, make sure to pay attention to the output of the plugin, it should only show warnings, otherwise it won't generate you classes and you will get a generic ClassNotFound exception but the cause can be something not allowing your plugin to compile well.
[INFO] --- maven-processor-plugin:3.3.3:process
...
7 warnings
Also make sure you don't have any version of mapstruct library older than 1.3.0.Final in you classpath, that will also cause issues preventing classes from generating.
I used the following configuration for JDK11
<properties>
<mapstruct.version>1.3.1.Final</mapstruct.version>
<maven.compiler.version>3.6.1</maven.compiler.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
Then mvn clean install will generate the impl classes in target\generated-sources\annotations

Add Argument "--add-modules" to Tycho Compiler

I inherited a Tycho projekt which gets built with Java 8 but runs with Java 10. For reasons it should now be built with Java 10 as well. The problem is with all the missing JDK bundles with exceptions like
[ERROR] The type javax.xml.bind.annotation.XmlElementWrapper cannot be resolved. It is indirectly referenced from required .class files
I now want to add --add-modules=ALL-SYSTEM to the Tycho compiler (like it already is in the *.product file). However that doesn't seem possible. I tried:
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-compiler-plugin</artifactId>
<version>${tycho-version}</version>
<configuration>
<argLine>--add-modules=ALL-SYSTEM</argLine>
<compilerArgument>--add-modules=ALL-SYSTEM</compilerArgument>
<compilerArgs><compilerArg>-add-modules=ALL-SYSTEM</compilerArg></compilerArgs>
</configuration>
</plugin>
Adding the dependency to Maven (I hoped this would bypass the need for an import package) and pomDependencies=consider:
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.8</version>
<scope>provided</scope>
</dependency>
</dependencies>
Aaand of course something like just passing it as a VM argument. Nothing works.
Most questions for this subject only focus on how stupid the idea is (it indubitably is), but there is no time to switch the project over to Java 10 (or something a bit more up-to-date).
So how do I add compiler arguments to Tycho?
You can configure compiler arguments like this:
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-compiler-plugin</artifactId>
<version>${tycho-version}</version>
<configuration>
<compilerArgs>
<arg>--module-path</arg>
<arg>${java.home}/jmods</arg>
<arg>--add-modules</arg>
<arg>java.smartcardio</arg>
</compilerArgs>
</configuration>
</plugin>
See also this question and this bug report. They deal with the problem telling the java compiler to find the modules.

New at Maven: Using the shade plugin and 3rd party jars

This should be pretty simple, but I can't the around to it. I need to create an uberjar using 3rd party jars. I've already followed these instructions: Including a non-Mavenized dependency so it works with maven-shade-plugin and added them to the local repository. But now what? Every Maven tutorial/example is kinda shady (pun intended) and I just don't know how to edit the .pom file properly in order to make it work.
Besides, I'm confused about the shade "plugin" overall. I mean, I followed the basic Maven tutorials and it went all fine and dandy. But when I look into the shade plugin page, I can't find it to download, except for the source code. I mean, isn't it a plugin? Shouldn't I download the binaries and install it into Maven somehow?
Sorry about the extreme noobish question but, needless to say, I know squat about Maven.
To create your shaded (uber) jar, you just need to declare the shade plugin in your pom.xml.
With regards to installation of the shade plugin, simply declaring it in the plugins section of your pom.xml is all you need do. Maven plugins are not installed manually, but are automatically downloaded by Maven (if not already downloaded; just like dependencies), stored in your local repository, and used whenever a project needs them.
As to using it, much like other plugins, declare it in your pom.xml by adding a <plugin> element with your configuration needs. This plugin does nothing automatically (some do, some don't) - you have to specify which "goal" to execute (think "method of a class"), and in which "phase" (think "step" of the build process). Unless you have strange needs, specify the "shade" goal in the "package" phase (see below).
For more configuration possibilities, see the shade usage page, and their examples (especially selecting contents for uber jar). Here is a simple example which, when you run mvn package, replaces your original jar in the target/ directory with the uber jar. It only includes the runtime dependencies, not the ones used at test time (notice the <scope> element of the junit dependency, which is not included in the uber jar).
<project>
<groupId>com.sample</groupId>
<artifactId>test</artifactId>
<version>1.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>test-core</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
If you have already downloaded the binaries and installed them into your local Maven repository all that remains is to declare them as dependencies in the POM. If the shade plugin is also declared in the POM a simple "mvn install" should generate a standalone JAR in the target directory.

How do I get Maven to fail when conflicting versions of the same artifact are referenced?

I'd like my Maven build to fail if the same artifact is referenced with different versions in my dependency tree. This would seem like a fairly trivial option, but I can't work out how to do it. Any clues?
The maven-enforcer-plugin has a dependencyConvergence rule which does what you want. Here's an example from the documentation.
This will cause a build to fail:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.6.0</version>
</dependency>
</dependencies>
With this being logged during compilation:
[ERROR]
Dependency convergence error for org.slf4j:slf4j-api:1.6.1 paths to dependency are:
+-org.myorg:my-project:1.0.0-SNAPSHOT
+-org.slf4j:slf4j-jdk14:1.6.1
+-org.slf4j:slf4j-api:1.6.1
and
+-org.myorg:my-project:1.0.0-SNAPSHOT
+-org.slf4j:slf4j-nop:1.6.0
+-org.slf4j:slf4j-api:1.6.0
The Maven Dependency Plugin will include a new dependency:analyze-duplicate in its version 2.2 and this is IMHO the closest thing you can get without specific development (it won't fail the build but will list duplicate dependencies).
This goal has been added for MDEP-206 (Add new Mojo to find duplicate dependency declared), which is fixed, but the version 2.2 has yet to be released so if you want to use this feature, you'll have to build a SNAPSHOT from the source tree:
https://svn.apache.org/repos/asf/maven/plugins/trunk/maven-dependency-plugin/
If you really want to fail the build in case of duplicate, either write your own mojo (extend the above one) or submit a RFE of the Maven Dependency Plugin.
As a side note, Maven 3 does Throw [a] Validation Error if pom contains a dependency with two different versions out of the box. To be totally accurate, this will be reported as warning in Maven 3.0 to not break existing Maven 2.x builds (see MNG-4005) and will be increased to error in 3.1 (see MNG-4622).
You can have the build fail on dependency analysis warnings using the dependency plugin.
See
http://maven.apache.org/plugins/maven-dependency-plugin/examples/failing-the-build-on-dependency-analysis-warnings.html
Add the following plugin:
Source: http://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<configuration>
<rules>
<dependencyConvergence/>
</rules>
</configuration>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>

maven dependencies groovy

I'm running a project that has a dependency on groovy 1.7-beta-1. The gmaven plugin uses groovy version 1.6 as a dependency. In my pom, I specify in the dependency management section the grooyv-all version as :
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7-beta-1</version>
</dependency>
</dependencies>
</dependencyManagement>
Yet when I run maven in debug mode I see that groovy 1.6 is being used for a dependency to the gmaven plugin. I thought my dependency management section would override this so they all use 1.7-beta-1, but I'm getting errors due to the different groovy versions. any help here would be appreciated.
thanks,
Jeff
Here's a refined version of Pascal's answer. I upgraded the main plugin version to 1.2, the dependency to Groovy 1.7, and wrapped it all in a pluginManagement tag so that it will nicely leverage the inheritance model.
Keep in mind that the 1.3-SNAPSHOT of the GMaven plugin has already begun using the 1.7-rc2 Groovy provider.
<!-- I wrapped everything in a plugin management section so that this can be neatly inherited across all your poms -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<!-- Notice I upgraded it to 1.2 -->
<!-- Details here http://repo1.maven.org/maven2/org/codehaus/gmaven/gmaven-plugin/1.2/gmaven-plugin-1.2.pom -->
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
Overriding a dependency used by a plugin is a nice ability that was actually introduced by Maven 2.0.9.
To do so, at least with a plugin that you are using as a normal build plugin - as opposed to a report which is not the case with the the gmaven-plugin so I won't cover this case here - simply add a dependency block inside the plugin block, like this (this is a sample so versions may be inaccurate):
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7-beta-1</version>
</dependency>
</dependencies>
</plugin>
As long as the new version of the dependency is "API compatible" with the version the plugin was linked against, you should be ok. If not, then you'll obviously have to upgrade to a newer version of the plugin compatible with the new API (i.e. likely using it as dependency), which is what you did.
To make gmaven accurately picks the right runtime is by configuring the "providerSelection" value, e.g.
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<configuration>
<providerSelection>1.7</providerSelection>
</configuration>
FYI, for the groovy:providers mojo, these are the configurations it expects (I extracted them by debugging to org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(List, Stack, MavenSession, MavenProject) (look for XmlPlexusConfiguration):
<configuration>
<remoteRepositories implementation="java.util.List">${project.pluginArtifactRepositories}</remoteRepositories>
<project implementation="org.apache.maven.project.MavenProject">${project}</project>
<artifactRepository implementation="org.apache.maven.artifact.repository.ArtifactRepository">${localRepository}</artifactRepository>
<pluginArtifactMap implementation="java.util.Map">${plugin.artifactMap}</pluginArtifactMap>
<providerSelection implementation="java.lang.String">${gmaven.runtime}</providerSelection>
</configuration>
You need to add a similar 1.7 dependency to the dependencies of the plugin in a similarly structured <plugin> or <pluginManagement> section. Your dependency management section you are adding is proper, but does not affect the plugin dependencies. I'll try to review this reply and post an example later when I'm back at my desk.