`class file has wrong version` after Jenkins upgrade - java

A couple of days ago, I upgraded Jenkins to version 1.643. Before, we were using Jenkins 1.593. Starting with Jenkins 1.612, Jenkins requires Java 7, see changelog, announcement and issue. Our Jenkins server has Java 8.
I have a Maven project consisting of submodules.
In the job configuration in Jenkins, I have configured the build to use JDK 1.6.
When looking at the build environment, it's indeed 1.6:
JAVA_HOME=/var/lib/jenkins/tools/hudson.model.JDK/1.6
One of the submodules fails to build on Jenkins, with this error:
[ERROR] /var/lib/jenkins/<REDACTED>.java:[15,-1] cannot access java.lang.Object
bad class file: java/lang/Object.class(java/lang:Object.class)
class file has wrong version 52.0, should be 50.0
According to what I can Google, class file version 52.0 is JDK 1.8 while the compiler is expecting version 50.0, which is JDK 1.6. I assuming that class file 52.0 refers to rt.jar (Java Runtime) which contains java.lang.Object (see also pom.xml snippet below).
I have found this SO question (and others that are duplicate of it), but they are all in the context of someone building from their IDE (IntelliJ) or from command prompt, and after reading them, I don't see how I could apply the suggested solutions. They involve setting $JAVA_HOME, which is already done by Jenkins.
My question is different because the issue is in the context of Jenkins (and Maven), and only occurred after the Jenkins upgrade. When I execute mvn clean install on my own desktop (with JDK 1.8), the error does not occur. If I execute the file command on the offending class file, but on the desktop where compilation succeeded, I get compiled Java class data, version 50.0 (Java 1.6). For me, this confirms that my pom.xml is (probably) still correct and it's (probably) a Jenkins configuration issue.
That specific submodule has this in the pom.xml, which may or may not be relevant:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
So, as you can see, it takes rt.jar from the current $JAVA_HOME so it can cross compile with a target of 1.6.
I'm a bit lost about the origin of this Java 8. Before the Jenkins upgrade, we were already using Java 8 on the server and cross compiling with a target of Java 6. What am I missing here?
EDIT
Do I even need this? If I comment out
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
in pom.xml, I can still cross compile on my desktop and the class files are still version 50.0.
EDIT
When I take that part out, the build does not fail any more.
Which means I solved it myself.
I want to change the question to: why did it fail in the first place? And why didn't it fail before on Jenkins 1.593?

I changed my pom.xml to exactly how it is described in this SO answer: Maven release plugin: specify java compiler version
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</configuration>
</plugin>
</plugins>
</build>
As you can see:
I explicitly set the groupId
I explicitly set the version to the latest version, 3.3
The configuration parameters are formatted a bit differently.
My educated guess is that the Maven on the Jenkins server didn't pick up configuration inside compilerArguments and was only happy when it is directly inside configuration. I leave it to the comments to explain how and why, but for me the issue is solved.

I think you have a few errors in your assumptions.
compilerArguments is deprecated. It's been superseded by compilerArgs.
Like you can see from compiler plugin documentation, compilerArguments/compilerArgs is meant to be used only for arguments not supported by configuration section itself. As bootclasspath is supported, using it in compilerArgs/compilerArguments section is generally incorrect.
compilerArgs/compilerArguments is only used if fork is set to true, which was not correct for your configuration.
The third point was probably the most important reason why it didn't work for you. Using configuration section for your use case there should be no issues, and indeed based on your question/answer, this seems to be the case.
Also note that java.home is not JAVA_HOME. I've expanded on that on my other answer here. I'd guess that is related to why you see changes between Jenkins versions.

Related

Compiling for execution under JRE 6 with Maven

I have a requirement to compile an app for use under JRE 6.
Initially the app was compiled for use under JRE 8.
So I added:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties>
to pom.xml
After fixing all the errors caused by unavaiable diamond operator, string in switch statement etc. I ran the app under JRE 6 and got the error.
Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: java/nio/file/Paths
Ok. This class is available only since Java 7. But the question arises: what does the above maven setting exactly? Does it only check the syntax? If so, then it's not quite useful.
What needs to be done to configure maven so that it notifies me about missing classes in particular Java version too?
java.nio.file.Paths was introduced in Java 7. You will have to change the implementation of your code to only use classes available in Java 6.
And yes, the Maven property only tells javac to use Java 6 syntax. That's very useful. Maven will not magically change your code for you. javac started by mvn package will tell you about unresolveable imports.
The purpose is to instruct maven to pass the -source and -target to the javac compile executable. It makes sure you only use language features that are available in the given JRE (the diamond operator is a great example), but it does not prevent use of APIs that only came along later.
Have a read of this
In particular the part at the bottom of the page:
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...
I think it's unfair to say the parameters are not useful they certainly are. But they are not magical tools that know which libraries may be available at runtime.
The Animal Sniffer plugin for maven verifies that classes compiled with a newer JDK/API are compatible with an older JDK/API.
https://www.mojohaus.org/animal-sniffer/
Ok. I figured out how to do it.
You don't have to install the target JDK or JRE. All you need is rt.jar from that JRE.
Then you have to set the path to the jar file in bootclasspath in pom.xml.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<compilerArguments>
<verbose />
<bootclasspath>C:/data/tmp/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>

Eclipse project: Maven Eclipse Plugin set wrong JRE class path container

I have an Eclipse Mars 2 Java8, Maven 3.5.4 based workspace.
I build the project files with mvn eclipse:clean eclipse:eclipse, and watch the following maven output:
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-**1.7**
The default JRE for the workspace isn't Java 7, it is Java 8, like you can see looking at the following Eclipse config file:
<workspace>\.metadata\.plugins\org.eclipse.core.runtime\.settings\org.eclipse.jdt.launching.prefs.
that contains the following data:
org.eclipse.jdt.launching.PREF_VM_XML=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?>
<vmSettings defaultVM\="57,org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType13,1538040823497*">
<vmType id\="org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType">
<vm id\="1431694854640" name\="jdk1.7.0_40" path\="C\:\\Program Files\\Java\\jdk1.7.0_40"/>
<vm id\="1447417000092" name\="jdk1.6.0_45" path\="C\:\\Program Files\\Java\\jdk1.6.0_45"/>
<vm id\="1538040823497" name\="jdk1.8.0_65" path\="C\:\\Program Files\\Java\\jdk1.8.0_65"/>
</vmType>
</vmSettings>
As you may notice by looking at the above configuration, the default VM has the vm id "1538040823497", which is named jdk1.8.0_65, and resides in C\:\\Program Files\\Java\\jdk1.8.0_65.
This VM is correctly registered as Workspace Default in Eclipse Preferences, Java/Installed JREs, is marked as a "perfect match" within the Execution Environment JAVASE-1.8.
I cannot see anything why Maven Eclipse Plugin considers
org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7 as the correct choice, and not JAVASE-1.8.
I already deleted all JREs and registered them newly.
Now there's exactly one 1.6, 1.7 and 1.8 Environment, each with a "perfect match", and 1.8 is checked as default (as you can see above).
I have to manually correct the project each time I generated it (Edit Build Path, change JRE library from 7 to 8), since all files using Java 8 features like streams or lambda functions signal compiler errors unless I assign the correct JRE manually.
I already tried and manipulate org.eclipse.jdt.launching.prefs, redefine all JREs, pray, curse or ask an Ouija board, to no avail, always Java 7 is assigned by the eclipse plugin (version 2.10, by the way).
Any ideas, anyone?
In your pom file, try to use this:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
You may also reference this link:
https://dzone.com/articles/maven-eclipse-and-java-9
Or if all fails, try eclipse oxygen, a newer version (not the newest release but much better than Mars IMO) that has Maven Integration plugin pre-installed, all you need is to add a m2e-connector plugin.

IntelliJ won't accept Java8 and diamonds at the end of List/Map

I'm using the latest JDK and everywhere from project creation to now everything is set to Java8 or SDK 8.
Still, intelliJ gives me this issue:
The red lamp tells me to change to Java7.
This is my project settings:
and this is the Modules section:
As you can see; I specifically changed it from the SDK default to java 8 when I got the error, but no result.
The compiler settings look like this:
I'm on a macbook and the intelliJ is the community version. Does anyone know why this is happening and how I fix it?
Try to run the project, if this is your error message:
Then I suggest you have a little look into your pom-file.
This project was built using the intelliJ maven project setting, and it was missing this lovely line of code:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
IntelliJ doesn't (at least in my case) generate the version in the pom (despite that I picked all the settings for it).
I tried specifying the compiler version in the plugin too, to no avail. Have you tried invalidating the cache? It's File -> Invalidate Caches/Restart.... I would probably restart as well for good measure.

java.lang.VerifyError: Expecting a stackmap frame at branch target JDK 1.7 with goal site

On upgrading our project to JDK 7 and JEE7 I'm hurt with Verification Error, but without any usable information in the log, even with the debug flag turned on. I'm using the latest maven version available, i.e. V3.2.5 with all plugins having the latest version of today! Eclipse Luna and jdk1.7.0_76 64 bit from Oracle on win7. The VM argument -XX:-UseSplitVerifier suggested in other answers doesn't change any thing! But what I can say for sure is: With the maven goals: package, install or deploy given no Verification Error happens and every Junit test comes out green. The Verification Error shows up with the goal „site“ given! Then not a single JUnit test passes! Useless to say that the problem never appeared with JDK 6 on the same project which started more than 3 years ago and which runs successfully in production at many sites! Who has an Idea what could go wrong on generating the reports for the site goal?
I was facing the same issue, used following configurations and it worked okay.
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<propertyName>jacoco.agent.argLine</propertyName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.10</version>
<configuration>
<argLine>-XX:-UseSplitVerifier ${jacoco.agent.argLine}</argLine>
</configuration>
</plugin>
java maven jacoco noverify

Jenkins Maven compilation fails due to JDK features unsupported? [duplicate]

This question already has an answer here:
Maven - use -source 5 or higher to enable... while building the project
(1 answer)
Closed 8 years ago.
Whenever I deploy a Jenkins build with Maven, it says that I have the 1.3 JDK, even though I have 1.7 installed.
Here is a picture of the error log I get when using an enhanced for loop:
http://gyazo.com/d1c7e297199dbf8a8b6ba23efa5733ba.png
However, I clearly have 1.7 JDK installed.
http://gyazo.com/27b85ba9ea25579aa714b0e2586fd618.png
If anyone knows why this issue occurs and how to fix it, please post below.
Sorry I don't have a ton of formatted information, but I have no idea why this could possibly be happening as I do not have such an outdated JDK and have the most recent updates from Oracle. Maven and Jenkins are also updated completely.
Thanks.
The complaint of maven is not about your jdk version, but about the -source parameter of the compiler. Older Maven versions use a version of the maven-compiler-plugin, which uses -source and -target 1.3 by default.
So, what you need to do is configure you project to use higher source and target levels in order to use your for each loop:
(taken from https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html)
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
Note that simply setting the version of the maven-compiler-plugin would actually be sufficient, since for version 3.1 the default is 1.5, however it is good style to explicitly include the source and target version in your master pom.
You have the project set to compile with the default jdk according to your stack trace. Your default is your %JAVA_HOME% environment variable on the server which is probably set to an older jdk. In order to compile with the 1.7 jdk you have to specify this in your project config. Change jdk : (Default) to your 1.7 name.. which is jdk.
Or you can just go to the maven jdk and change it from (inherit from project) to jdk.
There is already an issue ticket open with jenkins related to this: https://issues.jenkins-ci.org/browse/JENKINS-755

Categories

Resources