Saturday, January 24, 2009

java.lang.UnsupportedClassVersionError: why is it thrown & how to resolve?


java.lang.UnsupportedClassVersionError: when is it thrown by a JVM & how to resolve it? 

UnsupportedClassVersionError
is (evidently a descendant of the Error class in Java) which subclasses java.lang.ClassFormatError which in turn subclasses java.lang.LinkageError (which is a direct subclass of java.lang.Error). This error is thrown in the cases when the JVM (Java Virtual Machine) attempts to read a class file and finds that the major and minor version numbers in the particular class file are not supported. This happens in the cases when a higher version of Java Compiler is used to generate the class file than the JVM version which is used to execute that class file. Please do notice that this is not true vice-versa which means you can comfortably use a higher version of JVM to run a class file compiled using an earlier version of Java Compiler. Let’s understand why? We'll see below a valid Java program and subsequently an alert and a stack trace of the error which are thrown as a result of the above explained situation which causes UnsupportedClassVersionError. FYI: The output (with explanation) of this sample program can be found here - an interesting try-catch-finally usage in Java >>


public class TestFinally {

      public static void main(String[] args) {
              
            try{
                  try{
                        throw new NullPointerException ("e1");
                  }
                  finally{
                        System.out.println("e2");
                  }
            }
            catch(Exception e){
                        e.printStackTrace();
            }
      }
}


The error alert and the stack trace if the right JVM is not used



java.lang.UnsupportedClassVersionError: TestFinally (Unsupported major.minor version 49.0)
      at java.lang.ClassLoader.defineClass0(Native Method)
      at java.lang.ClassLoader.defineClass(ClassLoader.java:539)
      at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
      at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
      at java.net.URLClassLoader.access$100(URLClassLoader.java:55)
      at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
      at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
      at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)


The minor and major version numbers are represented by the major_version and minor_version items respectively in a Java Class File structure. A combination of these two unsigned integers (both of length 2 bytes each) determines the particular version of the class file format. If a class file has major version number M and minor version number m, we denote the version of its class file format as M.m.

As per Java VM Spec, “A Java virtual machine implementation can support a class file format of version v if and only if v lies in some contiguous range Mi.0 v Mj.m. Only Sun can specify what range of versions a Java virtual machine implementation conforming to a certain release level of the Java platform may support.” For example: Implementations of version 1.2 of the Java 2 platform can support class file formats of versions in the range 45.0 through 46.0 inclusive.

Major version number of the class file formats of the popular Java versions are: J2SE 6.0 = 50, J2SE 5.0 = 49, JDK 1.4 = 48, JDK 1.3 = 47, JDK 1.2 = 46, JDK 1.1 = 45. Now you understand what in our example “major.minor version 49.0” signifies? It simply means we have used J2SE 5.0 for compiling the source code as the class file format is 49.0 where major_version is ‘49’ and minor_version is ‘0’.

Errors are never detected at compile time. This is quite easier to understand in this case – how can the compiler have the information at the time of compilation about which version of JVM would be used execute the compiled class file? It can't, right? So is the case with other errors as well. This is the reason why all the Errors are unchecked. The error alert also rightly shows that it's a JVM Launcher error.

How to resolve UnsupportedClassVersionError?

Whenever you encounter this error, do check if you’re using an earlier version of JVM to execute the class file than the corresponding version of compiler you used to compile the source code. The example shown here was compiled using Java 5.0 compiler, but when I tried to run using JVM 1.4, I got the above error. I just needed to switch either to a JVM version 5.0 or above OR needed to switch to a Java Compiler of JDK 1.4 or below (you of course need to make sure the source code is compatible with the corresponding version of the compiler otherwise you’ll start getting other compiler errors).

A higher JVM version doesn’t cause a problem in most of cases unless the class file format is quite old (and hence doesn’t lie in the supported range as specified by Sun for that particular JVM version ... as discussed above). But, it’s always a good practice to have both the Compiler and the JVM of the same version.

Liked the article? Subscribe to this blog for regular updates. You may also like to follow the blog to manage the bookmark easily and to tell the world that you enjoy GeekExplains. If interested then please find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark


8 comments:

Anonymous said...

Thanks, nice explanation.

Anonymous said...

THANKS FOR SOLVING THE PROBLEM

Anonymous said...

cheers, great explanation

Eulenspiegel said...

Good explanation!
Another question about this topic: do you know any statement I can write in my java-source-code to get a compiler error if I try to compile my source with a compiler newer than I expect?

I write a class to be used in a project where JRE1.5 is used. I do have 1.5 and 1.6 JDK on my machine and 1.6 is default (in the PATH for other reasons). I want to avoid compiling this single source with 1.6 accidentaly...

Thanks!

Geek said...

You may like to use Conditional Compilation here... maybe by using some custom Env variable (which should give you the version of the compiler) and compiling only when you have the preferred version... hope this helps!

Eulenspiegel said...

Thanks for the hint about Conditional Compilation!

I found the direct solution for my question as well:
You may call "javac" with the option "-target 1.5" to tell the compiler of any version >1.5 to build a class-file compatible with Java 1.5.

JP@classpath java tutorial said...

Nice article , you have indeed cover unsupportedclassversionerror with great details.by the way some time its not easy to shift to higher version of JDK due to some other dependency and best approach is to find the culprit classes or jar and get the compatible version of those jar based on your execution environment

Anonymous said...

Conditional compilation is nice way to include/exclude features which depends upon versions or any particular platform. we used a lot while developing J2ME games which needs to run on different devices with different configuration. you can also check How to avoid UnsupportedClassVersionError in Java this problem