Maven - Use JDK 7 to Compile for JVM 5
Solution 1
This answer is targeted at the title of the question, not to the specific problems of the question in detail.
I ended up using this solution in my project, which allows me to use the custom bootstrap classpath selectively, by activating a maven profile. I strongly recommend using a profile for this, because otherwise it makes the build fail for anyone that does not have the environment variable set (very bad, especially for an open source project). I only activate this profile in my IDE for the "Clean & Build" action.
<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>
Solution 2
Previous version of Java we not particularly good at supporting previous versions of Java. For Java 7 it appears to be much better.
Here is a program which should compile under any version.
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
$ javac -target 1.7 -source 1.7 Main.java
$ javac -target 1.6 -source 1.6 Main.java
warning: [options] bootstrap class path not set in conjunction with -source 1.6
1 warning
$ javac -Xbootclasspath:/usr/java/jdk1.6.0_29/jre/lib/rt.jar -target 1.6 -source 1.6 Main.java
$ javac -Xbootclasspath:/usr/java/jdk1.5.0_22/jre/lib/rt.jar -target 1.5 -source 1.5 Main.java
$ javac -Xbootclasspath:/usr/java/jdk1.4.0_30/jre/lib/rt.jar -target 1.4 -source 1.4 Main.java
$ javac -Xbootclasspath:/usr/java/jdk1.3.1_29/jre/lib/rt.jar -target 1.3 -source 1.3 Main.java
$ javac -Xbootclasspath:/usr/java/jdk1.2.2_017/jre/lib/rt.jar -target 1.2 -source 1.2 Main.java
$ javac -Xbootclasspath:/usr/java/jdk1.1.8_16/jre/lib/rt.jar -target 1.1 -source 1.2 Main.java
$ javac -Xbootclasspath:/usr/java/jdk1.1.8_16/jre/lib/rt.jar -target 1.1 -source 1.1 Main.java
javac: invalid source release: 1.1
Usage: javac
use -help for a list of possible options
$ javac -Xbootclasspath:/usr/java/jdk1.1.8_16/jre/lib/rt.jar -target 1.0 -source 1.0 Main.java
javac: invalid target release: 1.0
Usage: javac
use -help for a list of possible options
If you need to compile for a previous version of Java, you need to provide a bootclasspath, ideally for the version of Java you want to compile for. Java 7 appears to be able to support all the way back to Java 1.2
Solution 3
You can use the bootclasspath configuration option on the maven-compiler-plugin if needed:
<compilerArguments>
<bootclasspath>xxxxxxxxx</bootclasspath>
</compilerArguments>
You can read more about it here. See the note under the example.
Solution 4
The problem is with Java 7 backwards compatibility.
There are very few classes that don't preserve backwards compatibility due to impossible to resolve issues of different nature, DataSource happens to be one of them.
So, either you adapt your class to respect the new signatures (even when in backwards compatibility mode), or you'll be forced to use a different version of the virtual machine.
You can read further information here: http://www.oracle.com/technetwork/java/javase/compatibility-417013.html
Solution 5
To use multiple Jars in the Maven compiler options, use the ${path.separator} string between the jars:
<compilerArguments>
<bootclasspath>${env.JAVA5_HOME}/jre/lib/rt.jar${path.separator}${env.JAVA5_HOME}/jre/lib/jce.jar${path.separator}${env.JAVA5_HOME}/jre/lib/jsse.jar</bootclasspath>
</compilerArguments>
Alex Ciminian
Updated on June 20, 2022Comments
-
Alex Ciminian almost 2 years
I've been trying to get this to work for a while now but no luck yet.
I want to run with
JAVA_HOME
pointing to JDK7 but I want to compile a project for JVM 5. I've read through documentation, I've found similar posts on SO, but none of them seem to work in my setup.I first tried with setting just
target
andsource
but I got an error:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin>
[ClassName]
is not abstract and does not override abstract methodgetParentLogger()
inCommonDataSource
As far as I understood that class was updated in JDK 7 and the extra method that's throwing the error was just added. I need to use the runtime of JDK 5 that has the old implementation and everything should work fine. So I do this:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <verbose>true</verbose> <source>1.5</source> <target>1.5</target> <compilerArguments> <bootclasspath>${env.JAVA5_HOME}/jre/lib/rt.jar</bootclasspath> </compilerArguments> </configuration> </plugin>
I have JAVA5_HOME set correctly on my system, I can see it loading the correct classes in the log, but I hit another error:
[loading ZipFileIndexFileObject[c:\Program Files\Java\jdk1.5.0_22\jre\lib\rt.jar(*.class)]]
...
...
[ClassName]
error: packagejavax.crypto
does not existWhich is fair enough, since I didn't include
jce.jar
(cryptography classes) in thebootclasspath
. There is a thing that puzzles me, though. Even though thebootclasspath
contains only the Java 5 runtime, I have a lot of libraries from JRE7 in the classpath. They are not specified anywhere.[search path for class files: c:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\rt.jar,c:\Program Files\Java\jdk1.7.0_02\jre\lib\ext\dnsns.jar,c:\Program Files\Java\jdk1.7.0_02\jre\lib\ext\localedata.jar,c:\Program Files\Java\jdk1.7.0_02\jre\lib\ext\sunec.jar,c:\Program Files\Java\jdk1.7.0_02\jre\lib\ext\sunjce_provider.jar,c:\Program Files\Java\jdk1.7.0_02\jre\lib\ext\sunmscapi.jar,c:\Program Files\Java\jdk1.7.0_02\jre\lib\ext\zipfs.jar, ...]
If I try and add jce.jar (from JRE5), I get back to the first error:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <verbose>true</verbose> <source>1.5</source> <target>1.5</target> <compilerArguments> <bootclasspath>${env.JAVA5_HOME}/jre/lib/rt.jar${path.separator}${env.JAVA5_HOME}/jre/lib/jce.jar</bootclasspath> </compilerArguments> </configuration> </plugin>
The type [ClassName] must implement the inherited abstract method CommonDataSource.getParentLogger()
I also see no trace of
rt.jar
being loaded, but I don't get ajava.lang
not found error, so there are some classes being loaded on the classpath.I'll fix it temporarily by making a batch script that overwrites
JAVA_HOME
before building and sets it back afterwards, but I really want this done the right way. This doesn't seem as such an extreme use-case. :)What am I doing wrong here?
-
Alex Ciminian about 12 yearsEven if I use
<source>
and<target>
? I understood from the docs that this is what they're supposed to do - produce code compatible with other JVMs. -
user1568901 about 12 yearsYou can compile code for earlier JVMs under the latest JDK. It will produce the appropriate byte code and throw errors if you try to use language constructs not available in the target JVM. You just need to use extra caution as javac won't prevent you from using new methods/classes that aren't in the old JVM standard system...
-
Vishy about 12 years@AlexCiminian You are using the correct option, the problem is whether your
javac
supports this option. Java 5.0 & 6 were very poor at compiling for previous versions, however Java 7 appears to cover back to Java 1.2 If you use an older version of thert.jar
it should prevent you using methods/functionality which doesn't exist in your target version. -
Alex Ciminian about 12 yearsCheck out my examples, I'm using it that way but it doesn't work if I specify multiple jars. Am I missing something?
-
Alex Ciminian about 12 yearsWell, it 'works' if I specify
rt.jar
, but it breaks because of other dependencies needed from the runtime (jce.jar
). If I try to add both, it's as if I haven't specifiedrt.jar
at all (my last example). I've tried doing this only in Maven, I'll try in the command line, maybe it's a maven bug. -
Vishy about 12 yearsstrange, I just tried basically what you have without the
${env...
and it worked just fine. Can you try removing the environment variable? -
Alex Ciminian about 12 yearsNope, doesn't work. Tried it with the full path instead of the environment var, but it behaves the same in both cases (one jar, two jars).
-
Vishy about 12 yearsCan you clarify what you mean by "doesn't work". Can you try compiling with the
-X
option for maven to give you more debugging information? -
Alex Ciminian about 12 yearsI get the two errors listed in my post, under each configuration. If I specify just
rt.jar
it breaks because it doesn't findjavax.crypto
. If I try and give it both, I get back to the unimplemented method error (it's probably using the JRE7 classes instead of JRE5). If I give it justjce.jar
it breaks because it doesn't findjava.lang
- which is normal. I don't understand why it doesn't use the jre I'm feeding it if I try and specify multiple<bootclasspath>
jars. Do I need to alter theclasspath
? -
Vishy about 12 yearsI would try doing the same compilation on the command line to see if it gives you a more informative error message. Perhaps with a simpler example. (I was only compiling a hello World program)
-
Alex Ciminian over 10 yearsIf you take a look at my example, this is what I was doing.