Maven confused about JRE been used - java

I've created a project in eclipse and added maven dependencies. In Eclipse, it says that I am using JRE 1.5. Everything works fine in Eclipse, for instance, I can run my tests.
When I try to run mvn clean install from the terminal, it gives me the following error.
...generics are not supported in -source 1.3 (use -source 5 or higher to enable generics)...
Its seems that Maven thinks I'm using JRE 1.3 and cannot recognize generics or for-each loops.
How can I:
Validate my assumption that maven is using the wrong version.
Get Maven to compile my project.

Specify the correct version of your JRE in the Maven compiler plugin, by default your pom.xml file will inherit the compiler-plugin from the Maven super pom.xml which targets the 1.3 JRE.
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

Related

Ant Java task for Java 1.6

Our project uses ant tool to build maven project. We are using java 1.6 and 1.8 for different OS related release. The build works fine for java 1.8 and same is failing when using 1.6 because of versions-maven-plugin which maven downloading is latest and compiled in 1.7.
I tried copying org.codehaus.mojo version plugin of 2.4 in local repository but still maven looking to latest 2.7 version. Is there is way to specify version in ant java task
<java classname="org.codehaus.classworlds.Launcher" fork="true" dir="#{basedir}" resultproperty="#{resultproperty}" failonerror="true">
You can specify the version of versions-maven-plugin in a pluginManagement section, something like:
<pluginManagement>
<plugins>
<plugin>
<artifactId>versions-maven-plugin</artifactId>
<version>2.4</version>
</plugin>
</plugins>
</pluginManagement>
Refer to: Maven2: How to be sure Maven build is using a specific plugin version?
Here is the Maven documentation:
https://maven.apache.org/pom.html#plugin-management

#Override annotation on implemented method of interface in Java 5 code doesn't give a compilation error

I have a legacy Java 5 project that will still be maintained until at least 31 December 2017.
My default system JDK is 1.8.
JDK 1.5 is also installed, as described in Install Java 5 in Ubuntu 12.04 and https://askubuntu.com/questions/522523/how-to-install-java-1-5-jdk-in-ubuntu.
The POM contains (as described in https://stackoverflow.com/a/22398998/766786):
<profile>
<id>compileWithJava5</id>
<!--
NOTE
Make sure to set the environment variable JAVA5_HOME
to your JDK 1.5 HOME when using this profile.
-->
<properties>
<java.5.home>${env.JAVA5_HOME}</java.5.home>
<java.5.libs>${java.5.home}/jre/lib</java.5.libs>
<java.5.bootclasspath>${java.5.libs}/rt.jar${path.separator}${java.5.libs}/jce.jar</java.5.bootclasspath>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<compilerArguments>
<bootclasspath>${java.5.bootclasspath}</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
$JAVA5_HOME is set:
• echo $JAVA5_HOME
/usr/lib/jvm/jdk1.5.0_22
As far as I understand the magic that is Java+Maven, this should be a valid incantation of the maven-compiler-plugin to instruct JDK 1.8 to pretend to be JDK 1.5 and use the Java 5 boot classpath.
According to Why is javac failing on #Override annotation, JDK 1.5 will not allow #Override on implemented methods of an interface, only on overridden methods present in a super class.
In this commit the #Override annotation is used on the implemented method of an interface, so this is invalid Java 5 code:
private static class DummyEvent implements PdfPTableEvent {
#Override
public void tableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases) {
}
}
When I run
mvn clean compile test-compile -P compileWithJava5
I don't get a compilation error on the class that contains the #Override annotation. What am I missing here?
(Already tried: Animal Sniffer Maven Plugin, but that plugin doesn't look at compilation flags, only at the byte code.)
EDIT: This is what I currently have in my POM.
<profile>
<id>compileWithLegacyJDK</id>
<!--
NOTE
Make sure to set the environment variable JAVA5_HOME
to your JDK 1.5 HOME when using this profile.
-->
<properties>
<java.version>1.5</java.version>
<java.home>${env.JAVA5_HOME}</java.home>
<java.libs>${java.home}/jre/lib</java.libs>
<java.bootclasspath>${java.libs}/rt.jar${path.separator}${java.libs}/jce.jar</java.bootclasspath>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArguments>
<bootclasspath>${java.bootclasspath}</bootclasspath>
</compilerArguments>
<compilerVersion>${java.version}</compilerVersion>
<fork>true</fork>
<executable>${java.home}/bin/javac</executable>
</configuration>
</plugin>
</plugins>
</build>
</profile>
Run with
export JAVA5_HOME=/var/lib/jenkins/tools/hudson.model.JDK/1.5
mvn compile test-compile -P compileWithLegacyJDK
See accepted answer below for more details.
The core of the issue: Maven is still compiling your code with the JDK with which it is launched. Since you're using JDK 8, it is compiling with JDK 8, and to compile with another compiler, you need to use toolchains or specify the path to the right JDK.
Set up
To test this answer, you can have a simple Maven project with the following POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
<compilerArguments>
<bootclasspath>/usr/lib/jvm/jdk1.5.0_22/jre/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
with a single class to compile sitting under src/main/java/test, being:
package test;
interface I {
void foo();
}
public class Main implements I {
public static void main(String[] args) {
new Main().foo();
}
#Override
public void foo() {
System.out.println("foo");
}
}
This looks like a standard Maven project configured to use JDK 5. Notice that the class uses #Override on a method implementing an interface. This was not allowed before Java 6.
If you try to build this project with Maven running under JDK 8, it will compile, despite setting <source>1.5</source>.
Why does it compile?
The Maven Compiler Plugin is not at fault. javac is to blame. Setting the -source flag does not tell javac to compile your project with this specific JDK version. It instructs javac to accept only a specific version of source code. From javac documentation:
-source release: Specifies the version of source code accepted.
For example, if you specified -source 1.4, then the source code you're trying to compile cannot contain generics, since those were introduced to the language later. The option enforces the source compatibility of your application. A Java application that uses Java 5 generics is not source compatible with a Java 4 program using a JDK 4 compiler. In the same way, an application using Java 8 lambda expressions is not source compatible to a JDK 6 compiler.
In this case, #Override is an annotation that was already present in Java 5. However, its semantics changed in Java 6. Therefore, code using #Override, whether it is on a method implementing an interface or not, is source compatible with a Java 5 program. As such, running a JDK 8 with -source 1.5 on such a class will not fail.
Why does it run?
Onto the second parameter: target. Again, this isn't a Maven Compiler concern, but a javac one. While the -source flag enforces source compatibility with an older version, -target enforces binary compatibility with an older version. This flag tells javac to generate byte code that is compatible with an older JVM version. It does not tell javac to check that the compiled code can actually run with the older JVM version. For that, you need to set a bootclasspath, which will cross-compile your code with a specified JDK.
Clearly, #Override on a method implementing an interface cannot run on a Java 5 VM, so javac should bark here. But nope: Override has source retention, meaning that the annotation is completely discarded after compilation has happened. Which also means that when cross-compilation is happening, the annotation isn't there anymore; it was discarded when compiling with JDK 8. As you found out, this is also why tools like the Animal Sniffer Plugin (which enables an automatic bootclasspath with pre-defined JDK versions) won't detect this: the annotation is missing.
In summary, you can package the sample application above with mvn clean package running on JDK 8, and run it without hitting any issues on a Java 5 JVM. It will print "foo".
How can I make it not compile?
There are two possible solutions.
The first, direct one, is to specify the path to javac through the executable property of the Compiler Plugin:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
<compilerArguments>
<bootclasspath>/usr/lib/jvm/jdk1.5.0_22/jre/lib/rt.jar</bootclasspath>
</compilerArguments>
<compilerVersion>1.5</compilerVersion>
<fork>true</fork>
<!-- better to have that in a property in the settings, or an environment variable -->
<executable>/usr/lib/jvm/jdk1.5.0_22/bin/javac</executable>
</configuration>
</plugin>
This sets the actual version of the JDK the compiler should use with the compilerVersion parameter. This is a simple approach, but note that it only changes the JDK version used for compiling. Maven will still use the JDK 8 installation with which it is launched to generate the Javadoc or run the unit tests, or any step that would require a tool for the JDK installation.
The second, global, approach, is to use a toolchains. These will instruct Maven to use a JDK different than the one used to launch mvn, and every Maven plugins (or any plugin that is toolchains aware) will then use this JDK to perform their operation. Edit your POM file to add the following plugin configuration of the maven-toolchains-plugin:
<plugin>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>1.5</version>
</jdk>
</toolchains>
</configuration>
</plugin>
The missing ingredient is telling those plugins where the configuration for that toolchain is. This is done inside a toolchains.xml file, that is generally inside ~/.m2/toolchains.xml. Starting with Maven 3.3.1, you can define the location to this file using the --global-toolchains parameter, but best to keep it inside the user home. The content would be:
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.5</version>
</provides>
<configuration>
<jdkHome>/usr/lib/jvm/jdk1.5.0_22</jdkHome>
</configuration>
</toolchain>
</toolchains>
This declares a toolchain of type jdk providing a JDK 5 with the path to the JDK home. The Maven plugins will now use this JDK. In effect, it will also be the JDK used when compiling the source code.
And if you try to compile again the sample project above with this added configuration... you'll finally have the error:
method does not override a method from its superclass
Setting target to 1.5 when you use JDK 1.8 does not guarantee that your code will work on 1.5 as explained in the doc of the maven-compiler-plugin.
Merely setting the target option does not guarantee that your code
actually runs on a JRE with the specified version. The pitfall is
unintended usage of APIs that only exist in later JREs which would
make your code fail at runtime with a linkage error. To avoid this
issue, you can either configure the compiler's boot classpath to match
the target JRE or use the Animal Sniffer Maven Plugin to verify your
code doesn't use unintended APIs.

Maven can't change the library set by default

I have this problem when creating a maven project. I can't change the JRE library from J2SE-1.5 to Java-S.E 1.6 or 1.7 without errors. (and even with the J2SE-1.5, I have a warning)
I know that it's set by default, so I changed the maven compiler plugin.pom file but I still get the same error.
Here is what i modified in my pom.xml file:
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
Just changing the java version in your pom.xml is not good enough. You need to have the environment variable JAVA_HOME set to the version you intend to use. Maven uses this variable to build your project, so JAVA_HOME and the compiler plugin version must match.

Maven builds project with Java 1.6 even if 1.5 is specified [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Java version mismatch in Maven
I have a project which is configured to use Java 1.5 with maven:
mvn help:effective-pom
...
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
...
My machine has Java 1.6 installed, and Maven is using it:
mvn -v
...
Apache Maven 2.2.1 (r801777; 2009-08-06 20:16:01+0100)
Java version: 1.6.0_21
I have imported the project into Eclipse (using mvn eclipse:eclipse), and it is building it with Java 1.5, as specified in the POM.
Now if I mark an interface implementation method with #Override, which is disallowed in Java 1.5 but supported in Java 1.6, then Maven will build the project without errors, but Eclipse will mark the annotation as a compile-time error and refuse to build the project.
How can I either get Maven to really compile the project with Java 1.5, or get Eclipse to compile the project using the same settings as Maven?
It seems that newer versions of the JDK 1.5 ignore the #Override if it is in an interface implementation method: https://stackoverflow.com/a/2336850/256245 I guess that JDK 1.6 does the same if it is compiling using target 1.5. That´s the reason Maven does not complain about it.
To check if Maven is really compiling to Java 1.5, you should use Animal Sniffer Plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>check-java15-sun</id>
<phase>test</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java15-sun</artifactId>
<version>1.0</version>
</signature>
</configuration>
</execution>
</executions>
</plugin>
Since Eclipse have its own compiler implementation, I guess you would have to remove the #Override annotation from interface implementation methods to make him happy. The removal will not do any harm since the annotation was being ignored by the JDK.

Issus with building the java project using maven2

I am using maven2 to build the java project, when i issue the command mvn clean install i am getting the error could not parse error message: (use -source 5 or higher to enable generics).
In my eclipse environment i am using jdk 1.7 and the project is working fine. when i want to build the project i am unable to do that, think maven is taking java version 1.3 as default.
Any one please help me how to set the jdk versio to 1.7 in maven, to build the project successfully..
Apart from the jars mentioned in pom.xml i want to add add my own jar, how can i specify that in pom xml?
Thanks in advance..
In your pom.xml configure the maven-compiler-plugin to use 1.6:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>

Categories