Thou shall know the .class file version!

It is easy to have more than on JDK or JRE version(in particular JRE -- because of browser plugin downloads!) in the same machine. If you compile your Java source(s) with a JDK version and run the same with with an earlier JDK/JRE version, you could get an error that looks like this:


Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad version number in .class file

Now, how do I know what is the version of a .class file and what version of JDK I need to run the same? The section 4.1 of VM spec. edition 2 explains the "header" structure of every .class file:


ClassFile {
    	u4 magic;
    	u2 minor_version;
    	u2 major_version;
    	u2 constant_pool_count;
    	cp_info constant_pool[constant_pool_count-1];
    	u2 access_flags;
    	u2 this_class;
    	u2 super_class;
    	u2 interfaces_count;
    	u2 interfaces[interfaces_count];
    	u2 fields_count;
    	field_info fields[fields_count];
    	u2 methods_count;
    	method_info methods[methods_count];
    	u2 attributes_count;
    	attribute_info attributes[attributes_count];
    }

The magic of a .class file is 0xCAFEBABE. The following class takes a class file as input and prints the major, minor version of it and also prints minium JDK/JRE required to run the given class.

File: Version.java

import java.io.\*; public class Version { public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java version <.class file>"); System.exit(1); } if (! new File(args[0]).exists()) { System.err.println(args[0] + " does not exist!"); System.exit(2); } DataInputStream dis = new DataInputStream( new FileInputStream(args[0])); int magic = dis.readInt(); if (magic != 0xcafebabe) { System.err.println(args[0] + " is not a .class file"); System.exit(3); } int minor = dis.readShort(); int major = dis.readShort(); System.out.println("class file version is " + major + "." + minor); String version = null; if (major < 48) { version = "1.3.1"; } else if (major == 48) { version = "1.4.2"; } else if (major == 49) { version = "1.5"; } else if (major == 50) { version = "6"; } else { version = "7"; } System.out.println("You need to use JDK " + version + " or above"); } }

For example, after compiling the above class with JDK 1.5 and running it against itself prints the following:

java -cp . Version Version.class
class file version is 49.0
You need to use JDK 1.5 or above
Comments:

Isnt that "thou shalt" rather than "thou shall" :-)

Posted by Vijay Tatkar on July 28, 2006 at 01:56 PM IST #

Another "Thou shall" .. er... "Thou shalt" :-) ??

Posted by A. Sundararajan on July 28, 2006 at 02:57 PM IST #

Great idea. Some enhancement ideas... - include support for scanning entire .jar files - future proof it should another version of Java come out after 7. For example, print the major version number.

Posted by Jesse Wilson on July 29, 2006 at 12:08 AM IST #

Cool! Really useful.

Posted by Bharath R on July 29, 2006 at 05:06 AM IST #

But...but... Why create a specialised tool just for jar files? On Unix platforms at least, the "file" utility is designed for exactly this kind of thing.

So for example by adding the following lines to the "magic numbers" file that "file" uses:-

0       ulong           0xcafebabe      Java class file
>6      ushort          x               major version %d.
>6      ushort          <48             Requires JRE 1.3.1 or later
>6      ushort          =48             Requires JRE 1.4.2 or later
>6      ushort          =49             Requires JRE 1.5 or later
>6      ushort          =50             Requires JRE 6 or later
>6      ushort          >50             Requires JRE 7 or later

You can obtain the following output:-

$ file Hello.class
Hello.class:    Java class file major version 49. Requires JRE 1.5 or later

Caveat: Solaris doesn't have a way of specifying big-endian vs little-endian magic numbers so the example lines will only work on SPARC, not x86)

Posted by Pete on July 31, 2006 at 08:34 AM IST #

Post a Comment:
Comments are closed for this entry.
About

sundararajan

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Bookmarks
Links

No bookmarks in folder

Blogroll

No bookmarks in folder

News

No bookmarks in folder