Maven: Handling Builds for Differing source/target Versions - java

Two different maven Java projects (let's call them ProjectA and ProjectB) depend on the same library (also a maven Java project, all three projects are self-written). ProjectA needs the library to be compiled for Java 1.7, ProjectB for 1.8. So far I had the following configuration in my library's pom.xml:
<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>
</configuration>
</plugin>
</plugins>
</build>
Installing the library like this then allows me to build ProjectB but not ProjectA, as and are both set to 1.8. I can change those two fields to 1.7 to allow ProjectA to be built but not B.
I want to do proper version control, automated builds, etc. and hence can't always change the lib's source/target version before building a project. Maintaining two library release branches, so solving the issue via the version control system, is also annoying and does not seem elegant (that's my current approach which I'd like to change).
If I replace the version with a variable (e.g. ${jdk.version}) and use the command line flag -Djdk.version=1.7 when installing the lib ProjectA will, for some reason, still not build, claiming the lib is targeted at 1.8. So apparently this is not equivalent to manually putting the 1.7 into the pom.xml file.
How can one solve this problem elegantly? Why will maven/Java not properly target the library at 1.7 if I try to set the corresponding property via the command line?

Related

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.

`class file has wrong version` after Jenkins upgrade

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.

IntelliJ imports project from POM using wrong JDK version

We have a Maven based Android build, and we just made the switch from JDK 6 to 7.
This came with its share of IntelliJ problems though. What happens is that every time it detects a change in the POM, and reimports/refreshes the project, it returns to selecting the old "Module SDK", the one that's configured to use Java 6:
Even if I manually delete these SDKs from the "Platform Settings" dialog, they keep reappearing as "Maven Android API 19 Platform (N)" where N is the number used to disambiguate it from all the other (identical) SDKs.
I should mention that we do specify in the POM that Java 7 is targeted. I tried to set both the compiler plugin language level, and the maven.compiler.* properties (not sure if that accomplishes the same thing or not), without luck:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
shouldn't IntelliJ pick that up and always configure the project to use a Java 7 SDK? Am I missing something?
I noticed that the problem disappears when I remove any references to 1.6 SDKs entirely in IntelliJ. Not surprising I guess, but also not viable since I have other projects that still rely on the presence of a Java 6 SDK.
I encountered a very similar issue with Maven projects I'd created using IntelliJ (version 14.x in my case). I'd configured IntelliJ to use JDK 8 in the Project Settings but the IDE continued to highlight issues in my code (e.g. complaining about the usage of #Override).
It turns out that the Maven Settings take precedence here, which in my case defaulted to JDK 1.5 (hence the IDE redlines). Changing the settings here does resolve the issue, but only temporarily because they revert back whenever the Maven projects are reimported, or when IntelliJ is restarted.
The permanent fix is to explicitly declared the JDK version in your Maven pom file, as explained in these items.
stop IntelliJ IDEA to switch java language level everytime the pom is reloaded (or change the default project language level) by #vikingsteve
IDEA: javac: source release 1.7 requires target release 1.7 by #bacchus
Here's what they've said you need to add to your pom.xml file.
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
These settings get reflected in the Maven Settings in the IDE and resolved the issue for me.
It will pick up the jdk that you choose in project structure please change it there.
File > project structure > project setting > project > project sdk choose 1.7.
If 1.7 is not present go to
File > project structure > Platform setting > SDKs addd 1.7 there.
It's also important to note that you need to change the runner (jdk level) of your maven.
Maven > Runner > JRE

Why eclipse doesn't see implemented interfaces?

I've imported jfreechart-fse from here: https://github.com/jfree/jfreechart-fse
and I've imported this to eclipse as maven project.
After that, I have many problems, for example in class ChartPanel in org.jfree.chart paskage, eclipse doesn't see "implements" section, and notice
#Override
public void actionPerformed(ActionEvent event) {...}
as a problem. The same situation is in many other cases.
Can you tell what is wrong with that?
Change version of java to 1.7. It resolves most of errors (errors still appear only in test directory in package-info.java files). Maven can build project successfully.
In eclipse you can change java version in project properties in Java Compiler tab or in properties of JRE System Library in your project tree.
pom.xml doesn't declare java version for maven compiler plugin.
J2SE-1.5 is used by default, and Override anotation cannot be used for Interface implementation for this version.
Change Eclipse project configuration to use JavaSE-1.6, or fix pom.xml of project before importing:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>

How to make Maven use Eclipse workspace default JRE?

I'm using Spring Tool Suite and m2e to convert some of our existing projects to Maven projects. The project in question uses jdk1.6.0_20 which is named [jdk1.6] in Eclipse. When I do Maven -> Update project, though, it replaces that jre with the standard [JavaSE-1.6]. While they seem to point to the same libraries, the change in name causes a bunch of exceptions like:
Access restriction: The type WindowsPopupMenuSeparatorUI is not
accessible due to restriction on required library C:\Program
Files\Java\jdk1.6.0_20\jre\lib\rt.jar
My pom.xml has this:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
Is there any way to get Maven/m2e to use the default workspace JRE instead of replacing it with a specific one in the .classpath?
Go into Configure Build Path on the project and go to the Libraries tab.
Remove the JRE System Library
Click on "Add Library..." and select "Workspace Default JRE"
That will give you the current JRE and not specify a specific JRE
Adding maven-compiler-plugin to your pom forces maven to use given version of Java:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
However if you have both jre and jdk installed on your system (for a particular java version), maven may choose jre and then complain that it needs JDK. This may happen after using Maven > Update Project in Eclipse.
To solve this, in Eclipse, right click on JRE System Library > Properties > Environments and select JavaSE-1.8. If you have more than one compatible JREs in your system then tick the jdk1.8.x > OK > select JavaSE-1.8 (jdk1.8.x) as Execution environment > OK
Now maven should choose Java version 1.8 and Eclipse will tell maven to use jdk1.8 as the default JRE for this java version.
It turns out there doesn't seem to be a way to do this with Maven. Instead I changed the error to a warning in Eclipse settings while I work with the owners of the offending code to fix the problems.

Categories

Resources