Tomee Maven Plugin Specify Java Binary - java

We are using the Tomee Maven Plugin for starting a Tomcat server and running some webapps. We need to use a specific version of Java, which is installed on the local system. Yet the Plugin picks the wrong Java version for starting Tomcat. We then get illegal argument exceptions due to the wrong Java version being used. How can we configure the Tomee Maven plugin to use a specific Java version?

Looking at the documentation there does not seem to be anyway to specify Java Version.
However each version of Tomee supports specific versions of Java, for example Java8/11, etc.
You could select the version that is suitable for your JDK version, as well ensure that your pom.xml has source/target for the specific java version you want:
<properties>
<tomee.version>7.0.2</tomee.version>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
You could also ensure that your maven compiler plugin uses the appropriate JDK:
<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>
</configuration>
</plugin>

Related

release version 1.8 not supported

I have a project that is using Java 8.
Up to now in the pom we specified the source and target version as 1.8:
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
We want to utilize the "-release" Option of Java 9+ and added the following:
<maven.compiler.release>1.8</maven.compiler.release>
But now we get the following error:
Fatal error compiling: release version 1.8 not supported
We are using maven 3.5.3, the maven-compiler-plugin in version 3.8.0 and Java 10 to compile the project.
What is wrong here?
This should work
<maven.compiler.release>8</maven.compiler.release>
since the <release> attribute works with the major versions of releases only.
By, the way this is assuming that this is a parameter used in the actual compiler-plugin configuration somewhat like :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
In my case I had to change release, source and target.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>8</maven.compiler.release>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

java 10 execution environment using eclipse photon and maven

I have a maven project using java 10 and I want to edit it in eclipse photon. It more or less works ok, but I do get the warning:
Build path specifies execution environment J2SE-1.5. There are no JREs installed in the workspace that are strictly compatible with this environment.
Setting the java compiler --> JDK compliance level to 10 in the project properties in eclipse doesn't remove this warning.
Is this an issue with the maven-compiler-plugin? I am currently using version 3.7.0 configured like so:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>10</source>
<target>10</target>
<release>10</release>
<encoding>UTF-8</encoding>
</configuration>
<dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>6.2</version> <!-- Use newer version of ASM -->
</dependency>
</dependencies>
</plugin>
Tips on how to configure a maven project using java 10 and eclipse photon would be greatly appreciated.
The issue seems to be with the JRE specified on the build path of your project. Right-click on the project and then go to Properties > Java Build Path > Libraries. There, edit the JRE System Library specified to JRE 10.
Actually, my problem was related to the version of Spring Tool Suite I was using. It turns out that I had upgraded my environment using the update site instead of downloading the new version. I was using Spring Tool Suite 4.7.3a instead of 4.8.0. Using 4.8.0 resolved the issue.

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

Does the POM file configuration overwrite the default settings of Spring Tool Suite configuration?

After checking this link No Compiler is provided in this environment
I observed that POM file configuration is overwriting STS default settings. This might be the reason whenever project is run on server, it is generating the error as mentioned in above link. This might be the code which is overwriting the STS default configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
This is a feature of the Maven support in Eclipse (which is also included in STS). It automatically maps your JDK version setting in your pom file to the compiler settings in Eclipse/STS. Otherwise you would end up having the IDE compile for a different JDK version than your Maven build - which would be a bit strange.

Maven confused about JRE been used

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>

Categories