Amber Beriwal
Amber Beriwal

Reputation: 1598

How to build java file on a particular minor version of JDK using eclipse?

If we see .class file structure, it says: offsets 0x04-0x05 are for minor version of JDK, and offsets 0x06-0x07 are for major version of JDK

I use eclipse for java project development with JDK1.5.0_7/JRE configured for JRE system library and class files shows offsets as 0x00 0x00 0x00 0x31.

How can I change the compiler to JDK1.5.0_7 so that offset becomes 0x00 0x07 0x00 0x31?

Upvotes: 0

Views: 1243

Answers (1)

SubOptimal
SubOptimal

Reputation: 22993

You cannot specify the minor number yourself during the compilation.

The major and minor number does not indicate the version of the JDK used to compile. They indicate the version of the class file format. Have a look at this SO answer.

The class file version also specify the version of JRE able to execute this class file. For example: if the major.minor version is 0x30.0x00 you need at least a JRE 1.4 to execute this class file. Which not in all cases mean a previous JRE couldn't understand the byte code. As soon you use a Java language feature/runtime class which did not exist in a previous Java version this isn't true anymore.

A simple example

public class Scratch {
    public static void main(String[] args) {
        System.out.println("foobar");
    }
}

This simple class can be compiled with a different then the default class file version of your JDK

Following would compile it for the version 1.4

javac -source 1.4 -target 1.4 Scratch

The generated bytecode would in this simple example still be the same. The lowest possible class file version for this simple example would be 2D.E (compile it with javac -target 1.1 -source 1.2 Scratch.java). And then a JRE 1.1 (verified with JRE 1.1.8) could run it.

To check the version you could use this snippet

import java.io.DataInputStream;
import java.io.FileInputStream;
public class ClassFileVersion {
    // add exception handling, left out only for the example
    public static void main(String[] args) throws Exception {
        String filename = args[0];
        try (DataInputStream in = new DataInputStream(new FileInputStream(filename))) {
            int magic = in.readInt();
            if (magic != 0xcafebabe) {
                System.out.println(filename + " looks not like a Java class file.");
            }
            int minor = in.readUnsignedShort();
            int major = in.readUnsignedShort();
            System.out.printf("majaor.minor: %X.%X hex  %d.%d dec%n", major, minor, major, minor);
        }
    }
}

edit

Here a small snippet to demonstrate the impact.

  1. compile the above Scratch.java with your current JDK
  2. run the class file minor version of the Scratch.class

    Path path = Paths.get("Scratch.class");
    byte[] bytes = Files.readAllBytes(path);
    bytes[5] = 1; // it was zero before
    Files.write(path, bytes, StandardOpenOption.TRUNCATE_EXISTING)
  3. run the changed class file java Scratch the execution will fail (error message might be differ in the wording, depending on your used JRE)

    java.lang.UnsupportedClassVersionError: Scratch has been compiled by a more recent
    version of the Java Runtime (class file version 52.1), this version of the Java Runtime
    only recognizes class file versions up to 52.0

If you compile the source for a lower major version (the -target option) an previous JRE could execute the bytecode (see the limitations mentioned earlier).

Assume you run this with JDK 8 javac -target 1.4 -source 1.4 Scratch.java. There are different things happen by the javac. First it checks if Scratch.java only use language features which were available in Java 1.4. Second the resulting Scratch.class get a major.minor class file version which was used in Java 1.4 (30.0 hex). Then you could run this class with the JRE 1.4 as java Scratch.

Upvotes: 2

Related Questions