Different maven compiler versions for test and main - java

How can I configure the maven compiler to use java 5 for my test code and java 1.4 for my main code?

If you want to set compliance to the relevant Java version, you can configure the compiler plugin for each execution. Assuming Maven is using a JDK at least as current as the highest version you specify. By using properties you can override that configuration on the commandline or in a child if needed:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${compileSource}</source>
<target>${compileSource}</target>
</configuration>
<executions>
<execution>
<id>test-compile</id>
<phase>process-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<source>${testCompileSource}</source>
<target>${testCompileSource}</target>
</configuration>
</execution>
</executions>
</plugin>
...
<properties>
<compileSource>1.4</compileSource>
<testCompileSource>1.5</testCompileSource>
</properties>
If you mean using different compilers, that's a bit more involved. as you need to specify the path to the JDK and what compiler version you're using. Again these can be defined in properties. Though you may want to define them in your settings.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${compileSource}</source>
<target>${compileSource}</target>
<executable>${compileJdkPath}/bin/javac</executable>
<compilerVersion>${compileSource}</compilerVersion>
</configuration>
<executions>
<execution>
<id>test-compile</id>
<phase>process-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<source>${testCompileSource}</source>
<target>${testCompileSource}</target>
<executable>${testCompileJdkPath}/bin/javac</executable>
<compilerVersion>${testCompileSource}</compilerVersion>
</configuration>
</execution>
</executions>
</plugin>
...
<properties>
<compileSource>1.4</compileSource>
<testCompileSource>1.5</testCompileSource>
<compileJdkPath>path/to/jdk</compileJdkPath>
<testCompileJdkPath>path/to/test/jdk<testCompileJdkPath>
</properties>
Note it might make sense to define the compiler configurations in profiles, one for each JDK you support, so that your normal builds don't rely on properties being set.
Also, in Maven 3.x, you need to include the fork parameter when specifying the executable, e.g.:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<fork>true</fork>
<executable>${testCompileJdkPath}/bin/javac</executable>
<source>1.8</source>
<target>1.8</target>
</configuration>
</execution>
</executions>
</plugin>

I had no luck with the accepted answer compiling java 7 source and java 8 test sources using the maven-compiler-plugin, version 3.5.1. Because the compile plugin used the source / target parameter for both, main and test sources.
But I found out, there are separate configuration parameters for the test source and target.
So for me the solution that worked was
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<testSource>1.8</testSource>
<testTarget>1.8</testTarget>
</configuration>
</plugin>
</plugins>
</build>

I found a solution at least for my case.
I am writing a library that needs to be Java 1.7 compatible but relies on the nashorn engine in JDK 8 to test some of its features, which is a perfect reason for using different compiler/jdk version for main and test.
When talking about using different compiler/JRE version for main and test, say version A for main and version B for test and A is strictly smaller than B, we really want to achieve the following:
Make the IDE (in my case, the Eclipse) use the JDK version B during development for not introducing compilation error (red cross on your project icon).
Make JUnit tests runnable from within your IDE.
Make JUnit tests runnable from command line through mvn clean test which is required for releasing.
Compile sources in main using JRE A, which enables automatic detection of using new features from JDK B.
Free use of new features / new APIs from JDK B in test cases codes.
And the following pom declaration works (for example let A = 1.7 and B = 1.8):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<fork>true</fork>
<source>1.8</source>
<target>1.8</target>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<compilerArguments>
<source>1.7</source>
<target>1.7</target>
</compilerArguments>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<configuration>
<compilerArguments>
<source>1.8</source>
<target>1.8</target>
</compilerArguments>
</configuration>
</execution>
</executions>
</plugin>
Firstly, <source>1.8</source> <target>1.8</target> is a must to make Eclipse happy and using 1.8 for the project itself, as others pointed out that Eclipse has a still pending bug and does not support different JDK version in a single project natively.
Secondly, use <execution> to override the source and target arguments during source compilation and test source compilation. default-compile and default-testCompile are special names for compiler plugin.
Thirdly, be sure to use compilerArguments but not compilerArgs. As far as I know, only compilerArguments can be used to override argument settings during runtime.

Related

Ignore maven execution block which uses toolchain if ~/.m2/toolchains.xml is not present

I'm working on an open-source library which must work correctly on jre7. Since java 9 has been released, we decided to provide our modules with module-info.java files so that users can make use of them if they prefer to use the library with sdk 9 on jre9 (in this case they'll need to manually put in pom.xml this piece of code:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
I've tried to implement the solution provided by maven (https://maven.apache.org/plugins/maven-compiler-plugin/examples/module-info.html) to compile the entire code with jdk7 and to compile only module-info.java files with jdk9. Here is a piece of pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<!-- compile everything to ensure module-info contains right entries -->
<!-- required when JAVA_HOME is JDK 8 or below -->
<jdkToolchain>
<version>9</version>
</jdkToolchain>
<release>9</release>
</configuration>
</execution>
<execution>
<id>base-compile</id>
<goals>
<goal>compile</goal>
</goals>
<!-- recompile everything for target VM except the module-info.java -->
<configuration>
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
<!-- defaults for compile and testCompile -->
<configuration>
<!-- jdkToolchain required when JAVA_HOME is JDK 9 or above -->
<jdkToolchain>
<version>[1.7,9)</version>
</jdkToolchain>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>9</version>
</jdk>
</toolchains>
</configuration>
</plugin>
And I've properly configured ~/.m2/toolchains.xml file. It works perfectly well. But the thing is we need to skip the first execution block, where everything's compiled with jdk9 with module-info, because we don't want to make our users create toolchains.xml file and set up java 9. So what I am probably looking for is the workaround to skip the following code if toolchains.xml is not present in ~/.m2 directory and only execute the second execution block, in which module-info.java files are ignored. Is that even possible? I realise we can still keep two branches (one private with two executional blocks and use of toolchains and another public, which ignores module-info.java files completely, but it doesn't seem an elegant solution.
<execution>
<id>default-compile</id>
<configuration>
<!-- compile everything to ensure module-info contains right entries -->
<!-- required when JAVA_HOME is JDK 8 or below -->
<jdkToolchain>
<version>9</version>
</jdkToolchain>
<release>9</release>
</configuration>
</execution>
You can activate/deactivate certain parts of a pom using Maven profiles.
Wouldn't it be better to provide two different versions of your library, e.g. with version numbers 1.0.0-JDK7 and 1.0.0-JDK9. Then the consumer of your library can choose the right one for their purposes.

Maven How to show warnings of codes when compiling

I'm using maven to build a new project. There are some warnings in my codes which are underlined by yellow line. I wish maven could report these warnings in console. How can I accomplish that? Can I just add some parameters in the command such as mvn -XXX clean compile?
<showDeprecation>
Sets whether to show source locations where deprecated APIs are used.
Default value is: false
User property is: maven.compiler.showDeprecation
<showWarnings>
Set to true to show compilation warnings.
Default value is: false
User property is: maven.compiler.showWarnings
-- Maven Doku
As simple as mvn clean install -Dmaven.compiler.showDeprecation=true -Dmaven.compiler.showWarnings=true all in one line.
You could even remove the =true part because, when you add a maven parameter with -D it automatically sets its value to true, if not set to something else.
With maven 3.3.9, using the maven-compiler-plugin and Java 1.8, you need a <configuration> section like the following:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
I got this answer from here when none of the above worked for me: http://frequal.com/java/EnableWarningsInMaven.html
I am guessing you are using the compiler plugin. Have you tried this?
Use the maven compiler plugin in your pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>false</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgument>-Xlint:all</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
To get to see detailed logs in maven you can use the command line option
-X, --debug Produce execution debug output
e.g this can be used as
mvn clean install -X
Also if what you want to get in the logs is the compiler warnings (The value of the local variable a is not used). You can try modifying your project's pom.xml with the following -
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
... other plugins
</plugins>
</build>

How to make Maven use JDK1.8 instead of JDK1.6

I am new to maven, and I find that though I change the facet of the jdk of the project to 1.8, every time I "update maven",it will get back to jdk 1.6.
Why is that?
I installed jdk 1.8 in my windows, and I am using eclipse.
I read Specify JDK for Maven to use and add the following but it does not work.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>1.8</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
The version of the JDK that maven will use is set in the maven-compiler-plugin like so:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source> <!-- use java 8 -->
<target>1.8</target>
</configuration>
</plugin>
See Setting the -source and -target of the Java Compiler for more information.
Check the maven compiler plugin to specify source and target java version,
http://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html
Regards,
Prasanna
maybe too late, but it works for me:
<!-- we want JDK 1.8 source and binary compatiblility -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- ... -->
<!-- we want sources to be processed by a specific 1.8 javac -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<verbose>true</verbose>
<fork>true</fork>
<executable>${JAVA_1_8_HOME}/bin/javac</executable>
</configuration>
</plugin>
Your question help me a lot anyway :) Thanks :)
In a comment you asked:
So what about maven-enforcer-plugin, what is this to do?
According to that documentation for the plugin:
"This goal is meant to be bound to a lifecycle phase and configured in your pom.xml. The enforcers execute the configured rules to check for certain constraints."
In other words, it checks that certain constraints have been satisfied. It does not cause them to be satisfied.
In your example, the effect of the plugin should be to cause the build to fail if the Java version is not Java 1.8.
... and why it solves the thread "Specify JDK for Maven to use"?
The answer you are referring to says this:
"And it never harms to ... add maven-enforce-plugin to make sure the right jdk is used. This is a good practice for your pom."
As you can see, it does not state that maven-enforce-plugin "solves" the problem. It is actually providing a way to ensure that the problem has been solved ... and fail the build if it hasn't.

How to write Junit with Java 1.7 while running base code with 1.6

I would like to use java 7 in my tests and java 6 for the code. How to achieve this?
You can also set source and target in the execution phase testCompile of the maven-compiler-plugin. So try something like this
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>testCompileWithJDK7</id>
<phase>test-compile</phase>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</execution>
</executions>
</plugin>
You can set the jvm that is used by the maven-surefire-plugin to point to the java 7 executable.
See http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#jvm

Setup Java 6 annotation processing configuration for eclipse compiler with maven

What's the best way to setup the eclipse project compiler configuration for Java 6 annotation processors?
My solution is to setup the org.eclipse.jdt.apt.core.prefs and factorypath files manually. This is a bit cumbersome:
Reference the processor jar in the factorypath file
Configure the eclipse annotation processor output directory (org.eclipse.jdt.apt.genSrcDir property in org.eclipse.jdt.apt.core.prefs)
Add the eclipse annotation processor output directory as source folder
One problem is that eclipse generated sources will be compiled with maven. Only maven clean compile is reliable as it removes the eclipse generated source files. (Eclipse and javac generated source files could be out of sync.)
Is there are better solution to configure maven without eclipse generated source files at the maven source path?
<project>
<properties>
<eclipse.generated.src>${project.build.directory}/eclipse</eclipse.generated.src>
</properties>
<build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals> <goal>add-source</goal> </goals>
<configuration>
<sources>
<source>${eclipse.generated.src}</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<additionalConfig>
<file> <name>.factorypath</name>
<content><![CDATA[<factorypath>
<factorypathentry kind="VARJAR" id="M2_REPO/processor/processor.jar" enabled="true" runInBatchMode="false"/>
</factorypath>
]]> </content>
</file>
<file>
<name>.settings/org.eclipse.jdt.apt.core.prefs</name>
<content><![CDATA[
eclipse.preferences.version=1
org.eclipse.jdt.apt.aptEnabled=true
org.eclipse.jdt.apt.genSrcDir=${eclipse.generated.src}
org.eclipse.jdt.apt.reconcileEnabled=true
]]> </content>
</file>
</additionalConfig>
</configuration>
</plugin>
</plugins>
</build>
</project>
Update: You could try using the apt-maven-plugin. It currently provides three goals:
apt-process Executes apt on project sources.
apt:test-process Executes apt on project test sources.
apt:eclipse Generates Eclipse files for apt integration.
You can configure the goals to run as part of your build as follows:
<build>
...
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<goals>
<goal>process</goal>
<goal>test-process</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
By default the output directory is set to ${project.build.directory}/generated-sources/apt,
There is an open Jira against the compiler plugin to add APT support for Java 6, you can go and vote for it if this is something you want to to see in future versions.
I am using http://code.google.com/p/maven-annotation-plugin/ wich is simpler to configure. You can use it in two ways:
generate sources during compilation (configuration below)
generate sources "by hand" to src/main/generated and keep them on SCM
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<compilerArguments>-encoding ${project.build.sourceEncoding}</compilerArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<executions>
<execution>
<id>process-test</id>
<goals>
<goal>process-test</goal>
</goals>
<phase>generate-test-sources</phase>
<configuration>
<compilerArguments>-encoding ${project.build.sourceEncoding}</compilerArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>${project.build.sourceEncoding}</encoding>
<!-- Disable annotation processors during normal compilation -->
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
There is a simpler solution in Eclipse Juno (I'm not sure about previous versions). In Preferences / Maven / Annotation Processing there are three modes for annotation processing. It is disabled by default, but I've tested both other options and worked like a charm for me. This way, you don't need to configure APT processing for every project or modify its pom.xml.

Categories