12

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 and source 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 method getParentLogger() in CommonDataSource

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: package javax.crypto does not exist

Which is fair enough, since I didn't include jce.jar (cryptography classes) in the bootclasspath. There is a thing that puzzles me, though. Even though the bootclasspath 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 a java.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?

Community
  • 1
  • 1
Alex Ciminian
  • 11,398
  • 15
  • 60
  • 94

5 Answers5

6

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>
hoijui
  • 3,615
  • 2
  • 33
  • 41
3

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

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Even if I use `` and ``? I understood from the docs that this is what they're supposed to do - produce code compatible with other JVMs. – Alex Ciminian Feb 06 '12 at 21:14
  • 3
    You *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... – Brian Knoblauch Feb 06 '12 at 21:45
  • @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 the `rt.jar` it should prevent you using methods/functionality which doesn't exist in your target version. – Peter Lawrey Feb 07 '12 at 08:30
  • Well, 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 specified `rt.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. – Alex Ciminian Feb 07 '12 at 10:49
  • strange, I just tried basically what you have without the `${env...` and it worked just fine. Can you try removing the environment variable? – Peter Lawrey Feb 07 '12 at 12:40
  • Nope, 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). – Alex Ciminian Feb 07 '12 at 13:26
  • Can 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? – Peter Lawrey Feb 07 '12 at 13:32
  • I get the two errors listed in my post, under each configuration. If I specify just `rt.jar` it breaks because it doesn't find `javax.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 just `jce.jar` it breaks because it doesn't find `java.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 `` jars. Do I need to alter the `classpath`? – Alex Ciminian Feb 07 '12 at 13:41
  • I 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) – Peter Lawrey Feb 07 '12 at 14:36
1

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

1

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>
MaeseDude
  • 421
  • 4
  • 4
1

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.

Michael
  • 6,141
  • 2
  • 20
  • 21