41

Are there any Java APIs to find out the JDK version a class file is compiled for? Of course there is the javap tool to find out the major version as mentioned in here. However I want to do it programmatically so that that I could warn the user to compile it for the appropriate JDK

Community
  • 1
  • 1
Prabhu R
  • 13,836
  • 21
  • 78
  • 112
  • 1
    The answers that involve reading bytes from a file seem quite uncivilized to me. There ought to be a way to get this information using Reflection, such as Foobar.class.getTargetVersion(). – John Henckel Oct 01 '14 at 17:53

9 Answers9

59
import java.io.*;

public class ClassVersionChecker {
    public static void main(String[] args) throws IOException {
        for (int i = 0; i < args.length; i++)
            checkClassVersion(args[i]);
    }

    private static void checkClassVersion(String filename)
        throws IOException
    {
        DataInputStream in = new DataInputStream
            (new FileInputStream(filename));

        int magic = in.readInt();
        if(magic != 0xcafebabe) {
            System.out.println(filename + " is not a valid class!");;
        }
        int minor = in.readUnsignedShort();
        int major = in.readUnsignedShort();
        System.out.println(filename + ": " + major + " . " + minor);
        in.close();
    }
}

The possible values are :

major  minor Java platform version 
45       3           1.0
45       3           1.1
46       0           1.2
47       0           1.3
48       0           1.4
49       0           5
50       0           6
51       0           7
52       0           8
53       0           9
54       0           10
55       0           11
56       0           12
57       0           13
58       0           14
59       0           15
60       0           16
61       0           17
62       0           18
63       0           19

ref : The Java Virtual Machine Specification, Java SE 19 Edition

RealHowTo
  • 34,977
  • 11
  • 70
  • 85
20

basszero's approach can be done via the UNIX command line, and the "od(1)" command:

% od -x HelloWorldJava.class |head -2
0000000 feca beba 0000 3100 dc00 0007 0102 2a00
0000020 6f63 2f6d 6e65 6564 6163 642f 6d65 2f6f

"feca beba" is the magic number. The "0000 3100" is 0x31, which represents J2SE 5.0.

rickumali
  • 707
  • 8
  • 17
16

On Linux, you can use the file command on a class file, which I found easiest for my use case. For example:

$ file Foo.class
Foo.class: compiled Java class data, version 50.0 (Java 1.6)
Daniel Wille
  • 539
  • 3
  • 10
9

Apache BCEL provides this API:

JavaClass c = Repository.lookupClass("com.x.MyClass")
c.getMinor();
c.getMajor();
skaffman
  • 398,947
  • 96
  • 818
  • 769
8

This gets you the contents of the class file:

MysteryClass.class.getResourceAsStream("MysteryClass.class")

Then look at bytes 5-8 to get the minor and major version. A mapping between those numbers and the JDK releases can be found here.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
6

Just read the class file directly. It's VERY easy to figure out the version. Check out the the spec and wiki and then try the code. Wrapping this code and making is more useful/pretty is left as an exercise. Alternatively, you could use a library like BCEL, ASM, or JavaAssist

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ClassVersionTest
{
    private static final int JAVA_CLASS_MAGIC = 0xCAFEBABE;

    public static void main(String[] args)
    {
        try
        {
            DataInputStream dis = new DataInputStream(new FileInputStream("Test.class"));
            int magic = dis.readInt();
            if(magic == JAVA_CLASS_MAGIC)
            {
                int minorVersion = dis.readUnsignedShort();
                int majorVersion = dis.readUnsignedShort();

                /**
                 * majorVersion is ...
                 * J2SE 6.0 = 50 (0x32 hex),
                 * J2SE 5.0 = 49 (0x31 hex),
                 * JDK 1.4 = 48 (0x30 hex),
                 * JDK 1.3 = 47 (0x2F hex),
                 * JDK 1.2 = 46 (0x2E hex),
                 * JDK 1.1 = 45 (0x2D hex).
                 */

                System.out.println("ClassVersionTest.main() " + majorVersion + "." + minorVersion);
            }
            else
            {
                // not a class file
            }
        }
        catch (FileNotFoundException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
basszero
  • 29,624
  • 9
  • 57
  • 79
2

As others have shown, it is easy enough to do by reading the first eight bytes of a class file. If you want a pre-built binary library, you can download one here.

McDowell
  • 107,573
  • 31
  • 204
  • 267
1

JavaP does have an API, but it's specific to the Sun JDK.

It's found in tools.jar, under sun/tools/javap/Main.class.

Robert Munteanu
  • 67,031
  • 36
  • 206
  • 278
1

I use this script in a batch file on windows, redirect the output and grep for the major number I am verifying for:

for /R %%f in (*.class) do (
"C:\Program Files\Java\JDK8\bin\javap" -v "%%f" | findstr major )

I run it as such:

verify.bat > versionResults.txt
Beezer
  • 1,084
  • 13
  • 18