Compile Maven Module with Different Java Version - maven

My maven project has a few modules: server, web, etc.
I would like to build all but my server module on Java 6. For the server module, I'd like to compile it with Java 7.
Here's my pom.xml below, but I think that if I modify it to 1.7, then all of my modules will be compiled with Java 7. Also, does maven use the JAVA_HOME environment variable to determine which Java version to use?
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<memmax>2048m</memmax>
</configuration>
</plugin>
EDIT Also, does the below output of
maven --version
indicate that maven is compiling my java code with 1.7?
vagrant#dev:~/bin/apache-tomcat-7.0.29/bin$ mvn --version
Apache Maven 3.0.4 (r1232337; 2012-01-17 08:44:56+0000)
Maven home: /home/vagrant/bin/apache-maven-3.0.4
Java version: 1.7.0_07, vendor: Oracle Corporation
Java home: /home/vagrant/bin/jdk1.7.0_07/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.2.0-23-generic", arch: "amd64", family: "unix"
Thanks,
Kevin

There are a number of hacks out there for compiling source code with a different version of the JDK than you are using to run Maven, for example you can use something like
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<executable><!-- path-to-javac --></executable>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
The issue with this approach is that you now have hard-coded the path to the JDK into your POM. Everything will work just fine on your machine but when you have to rebuild your machine because the HDD failed, or when you want to build on a different machine, you will be stuck as the path will most likely not match up.
The correct best practice way to handle this is via Toolchains. This will see you creating a ~/.m2/toolchains.xml file that describes where each of the different toolchains in your system are. Then the version of the JDK can be applied by the Maven Toolchains Plugin, e.g.
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>1.6</version>
</jdk>
</toolchains>
</configuration>
</plugin>
...
</plugins>
The next thing is that you don't need this as often as you would think. For example by using the source and target values you can generate the correct bytecode for the JRE that you are targeting... the only issue that you will then hit is the use of methods that are new in JRE 1.7... which is where Mojo's Animal Sniffer Plugin comes in. Animal Sniffer can be used to ensure that you only use the methods of the JRE that you are targeting. The general community consensus is that the use of source and target configuration options in the Maven Compiler Plugin configuration coupled with the use of Mojo's Animal Sniffer virtually eliminates the need for toolchains on the Compiler end of things.... on the Surefire end of things there is still need for toolchains... and I have a few edge cases that I need to update the compiler plugin and the toolchains plugins for to handle but, realistically you will not hit those edge cases ;-)
Just to be sure that your original question is completely answered (since the above answers the question you wanted to ask - as opposed to the one you asked)
At present you are compiling with JDK 1.7 however depending on the version of the Maven Compiler Plugin you are using, you may be compiling with either <source>1.4</source><target>1.4</target> or <source>1.5</source><target>1.5</target> unless you have changed the configuration of the Maven Compiler Plugin in your pom.xml. That will dictate which language features are available to you, but not which classes... so you would be generating code that will work on JRE 1.7 and provided you have not used any new classes/methods introduced since 1.4/1.5 (Such as String.isEmpty()) should also work on JRE 1.4/1.5... the only way to be sure if it works on such an old JVM is to either: run it on the old JVM OR use Animal Sniffer.

Maven Toolchains
To use multiple Java versions, you need to use Maven Toolchains, which require you to create a toolchains.xml file in your ~/.m2 Maven folder, containing all Java versions installed on your machine:
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<id>Java13</id>
<version>13</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_13}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java9</id>
<version>9</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_9}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java8</id>
<version>8</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_8}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java7</id>
<version>7</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_7}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java6</id>
<version>6</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_6}</jdkHome>
</configuration>
</toolchain>
</toolchains>
The JAVA_HOME_13, JAVA_HOME_9, JAVA_HOME_8, JAVA_HOME_7, JAVA_HOME_6 environment variables are configured so that they reference the path where the associated Java version is installed.
The FlexyPool parent pom.xml configuration file
The parent pom.xml Maven configuration file of the FlexyPool project defines the global Java version settings
<properties>
<jdk.version>8</jdk.version>
...
</properties>
Now, we need to instruct both the compiler and the test plugins to use the configured java version.
<build>
<plugins>
<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>${jdk.version}</version>
</jdk>
</toolchains>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
</plugins>
</build>
The FlexyPool child Maven module pom.xml using a different Java version
The flexy-pool-core-java9 child Maven module that requires a different Java version only needs to override the default jdk.version Maven property:
<properties>
<jdk.version>9</jdk.version>
</properties>
And that's it, we can now build each module using its own minimum viable Java version.

use the setup for the JDK6 on your top pom, it will be inherited by all the module, and overwrite it for your server pom with the different configuration required.
As for the path of the JDK, you can specify it, see here: http://maven.apache.org/plugins/maven-compiler-plugin/examples/compile-using-different-jdk.html

Related

Check Java Version/API compat in maven without installing old JDKs?

Is there a way to make sure that maven modules are API-compatible to older Java releases without installing and using the specific JDK release? Ie. some plugin?
Example: java.lang.String.isBlank() is available from JDK 11 only, so the plugin should check whether that method has been used if target version is <=10.
Alternatively, I could write a few plugin executions to download/unpack a jdk and then build the current project against that specific jdk. However, that'd be ugly.
the animal sniffer recommendation works great:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.17</version>
<executions>
<execution>
<id>verify-java-api</id>
<goals>
<goal>check</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java18</artifactId>
<version>1.0</version>
</signature>
</configuration>
</plugin>
Update: that animal sniffer configuration did not find this issue:
symbol: variable RELEASE_10
location: class javax.lang.model.SourceVersion

AEM - Maven project does not copy apps components package

I'm using AEM 6.1 and using maven(3.3.3) to build and deploy projects. Whereas, the maven buiild installs my bundle package, with the java code. It is not copying my components and templates folder (in the apps folder).
I have added the paths in the filter.xml. Can someone provide me a sample POM or structure of how we can achieve copying of the components during the build?
Thanks!
Was your Maven project created from an archetype? If so, there should be a autoInstallPackage profile defined. I suspect you may be using autoInstallBundle, which would only install your OSGI bundle.
If it wasn't, you need to configure the content-package-maven-plugin to deploy the generated CRX package to a target instance.
There should be sufficient information in the official Adobe documentation for managing packages with Maven but here's a sample config from Lazybone's aem-multimodule-project by ACS Commons.
Specify the contents of your CRX package:
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<group>${packageGroup}</group>
<filterSource>src/main/content/META-INF/vault/filter.xml</filterSource>
<embeddeds>
<embedded>
<groupId>${groupId}</groupId>
<artifactId>${bundleArtifactId}</artifactId>
<target>/apps/${appsFolderName}/install</target>
</embedded>
</embeddeds>
<targetURL>http://\${crx.host}:\${crx.port}/crx/packmgr/service.jsp</targetURL>
</configuration>
</plugin>
Specify a profile to use in order to install the package:
<profile>
<id>autoInstallPackage</id>
<build>
<plugins>
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<executions>
<execution>
<id>install-content-package</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Source:
https://github.com/Adobe-Consulting-Services/lazybones-aem-templates/blob/master/templates/aem-multimodule-project/content/pom.xml

How can I configure Maven to use JDK6 by default, but JDK7 as needed

I have both JDK 1.6 and 1.7 installed on my system (Linux, under the /opt directory).
I've added the bin directory for JDK 1.6 in my path, so that's the version of Java used by default.
I'm working on a project that requires JDK 1.7 and some that require 1.6. Previously I had set JDK 1.7 settings within Eclipse, but I wanted to convert this project to Maven so that everyone could use their preferred editor.
Is it possible to specify the 1.7 location on a Maven installation/configuration (and not in the POM file) such that it uses 1.6 by default and 1.7 when specifying the project requires it in the POM? As far as I am aware, everyone working on a project should have the same contents in their POM files, so I am reluctant to set the location of the Java 7 directory here (as it'll be different on everyone's machines).
$ mvn --version
Apache Maven 3.0.5 (r01de14724cdef164cd33c7c8c2fe155faf9602da; 2013-02-19 13:51:28+0000)
Maven home: /opt/apache-maven-3.0.5
Java version: 1.6.0_45, vendor: Sun Microsystems Inc.
Java home: /opt/jdk1.6.0_45/jre
Default locale: en_GB, platform encoding: UTF-8
OS name: "linux", version: "3.8.0-27-generic", arch: "amd64", family: "unix"
Adding the following:
<build>
<plugins>
<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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<outputDirectory>${project.build.outputDirectory}/resources</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
results in:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project golemlite: Fatal error compiling: invalid target release: 1.7 -> [Help 1]
Take a look here. You can set a property in your settings.xml and use it in the pom. Be aware that everybody would have to define that property.
As for your example:
<build>
<plugins>
<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>
<fork>true</fork>
<executable>${JAVA_1_7_HOME}/bin/javac</executable>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<outputDirectory>${project.build.outputDirectory}/resources</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
and in the settings:
<settings>
[...]
<profiles>
[...]
<profile>
<id>compiler</id>
<properties>
<JAVA_1_7_HOME>/path/to/jdk7</JAVA_1_7_HOME>
</properties>
</profile>
</profiles>
[...]
<activeProfiles>
<activeProfile>compiler</activeProfile>
</activeProfiles>
</settings>
You can place a file named mvn.sh near your pom.xml in which you set JAVA_HOME to anything you want. Then, build project like ./mvn clean install. And be sure not to check it to VCS.
Maven uses whatever version is in your JAVA_HOME system variable. So I like to add to my .bash_profile functions to swap between them just in my current shell, so you could leave Java 6 by default but allow yourself to trivially switch to Java 7 or even 8 when you need to build a newer project.
Gist to Change Java Versions on Demand
If your terminal is not bash then you may need to tweak this solution.
Personally I prefer this to setting it in your settings.xml even though it is slightly more work as it allows you to use the same solution across all build tools and even just for running jars built targeting other versions of Java.
So a solution for you might be adding something like this to your .bash_profile (clearly tweaking the paths appropriately to where ever the Java versions are installed on your machine):
function java6
{
JAVA_HOME=/Library/Java/JavaVirtualMachines/1.6.0_65-b14-462.jdk/Contents/Home
export JAVA_HOME
}
function java7
{
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home
export JAVA_HOME
}

How to appoint specific jdk version for maven to build my project?

My problem is: Test cases are green on local, but some are failed on hudson server because of non-supported jdk version. Local is ibm jdk1.6 sr4 windows, but hudson server installed ibm jdk1.6 sr9 linux. "This Java virtual machine is not supported for use with Blaze Advisor because the implementation of java.beans.Introspector failed to pass validation."
I was told Hudson server cannot change to other jdk, so I am think is there any work around to bypass those failure?
Can I tell maven to compile project with specific jdk? Like, 1.6 version with sr4, instead of sr9. Also I need maven to download sr4 as dependency coz there is no this version on server.
Seems it's hard to do this as I searched out. So what else option i could have?
Thanks for any suggestion.
Maven should start with the java specified in JAVA_HOME if you need to use a different version I would use the toolchain plugin to run your build with a specified jdk version. It will require the version be already installed on the server though.
http://maven.apache.org/guides/mini/guide-using-toolchains.html
You will need to add the plugin to your pom and add a toolchains.xml file.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>1.5</version>
<vendor>sun</vendor>
</jdk>
</toolchains>
</configuration>
</plugin>
toolchains.xml file added to .m2 folder which specifies the install location for the jdk
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.5</version>
<vendor>sun</vendor>
<id>default</id>
</provides>
<configuration>
<jdkHome>/path/to/jdk/1.5</jdkHome>
</configuration>
</toolchain>
Are you sure? The Hudson should support switching JDKs, I've done it in Jenkins. In worst case you could specify JAVA_HOME env variable in the Hudson build. It is impossible to change in maven, because maven itself needs JDK to start.
You can configure this in your maven-compiler-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.4</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
You can also use profiles -P to set versions based on environments.

Maven Install: "Annotations are not supported in -source 1.3"

When running mvn install on my project, i see it fail due to the following errors:
C:\Repositories\blah\src\test\java\com\xxx\qm\testrunner\test\ATest.java:[11,5] annotations are not supported in -source 1.3
(use -source 5 or higher to enable annotations)
#Test
C:\Repositories\blah\src\test\java\com\xxx\qm\common\test\BTest.java:[11,5] annotations are not supported in -source 1.3
(use -source 5 or higher to enable annotations)
#Test
My Maven dependency includes jUnit 4.8, however and has no reference to 1.3 anything.
What would cause these errors? Please advise
You need to specify the source version of your maven project through the use of the maven-compiler-plugin. Add the following to your pom build element and set the appropriate java source and target levels.
<build>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
http://maven.apache.org/plugins/maven-compiler-plugin/
A shorter version:
<project>
<properties>
<maven.compiler.source>1.5</maven.compiler.source>
<maven.compiler.target>1.5</maven.compiler.target>
</properties>
....
You are most likely using OpenJDK where the source level is 1.3 when not explicitly set - as opposed to Oracle JDK where the source level is 1.5.
Since most modern Java projects target newer code than Java 5 you most likely need to set this anyway.
Also note that if you need a lower target than source (e.g. for compiling with Java 6 but deploying to Java 5) you can do this by using the Eclipse compiler instead of Javac.
Bu default, the maven tries to compile using Java 1.3 version. I hope most of them hit this error because of missing to tell maven that "Hey Maven, Dont use 1.3 and use "whatever_version_I_give"
This can be mentioned in pom.xml as below :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
In my above example, I have used 1.7. Please replace with whatever version you wish to.
Add this in your pom
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<!-- put your configurations here -->
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

Resources