Java: Determining the Java version used to compile a class, ‘class file has the wrong version’

If a Java class file is compiled with a higher supported version than is currently being run, you will get the ‘bad class file’, ‘class file has the wrong version XX.0, should be XX.0’ error message.

For example, if the .class file was compiled as a Java 1.8 class file on a Jenkins continuous integration node, but the JRE on the desktop where you want to run it only has Java 1.7, then you will get this message when you attempt to run it.

The good news is that this is a relatively simple issue to address.

Quick Resolution

The easiest way to resolve this issue is to simply move up the higher Java version expected.  The error message indicates ‘should be XX.0’, and the table below shows which JVM to use.

But there are also times when for security reasons or enterprise standards, that you cannot upgrade your JVM just to accommodate a single class or library.  In these cases, you can look for older versions of the library or if the project is open-source, you can investigate recompiling at a lower level as long as newer features and packages are not utilized.

Background

Here is a table of the JVM versions mapped to the corresponding major version:

JVM Major Version (decimal)
Java 1.4 48
Java 5 49
Java 6 50
Java 7 51
Java 8 52
Java 9 53
Java 10 54
Java 11 55
Java 12 56
Java 13 57
Java 14 58

This major version number is stored in the header of the .class file, at byte 7.

Determining major version

If you have a JDK (Java Development Kit) installed on your machine, then you can use ‘javap’ to look into the class file.  Note that a JRE (runtime) will not have this utility available.

Linux:

$ javap -verbose MyClass | grep "major"

Windows:

> javap -verbose MyClass | findstr "major"

If you don’t have access to javap, you can also using a console based utility or GUI hex editor to look at the value of the byte at position 7 in the file.  Using Linux, this is easily done using the ‘od’ dump standard utility.

$ od --format=d1 MyClass.class -j 7 -N 1
0000007 51 0000011

Compiling to lower versions

Even if you are using a newer JDK, you can still compile code compatible with older JVM specifications by using the ‘-target’ parameter.  If you target a lower JVM, it is important that no features/packages from the newer specification are used.

For example, even if the ‘javac’ being used below is from a 1.8 JVM, it can still create 1.7 compatible class files if you use the parameters below.

$ javac -classpath . MyClass.java -source 1.7 -target 1.7

 

Compiling to lower versions using Maven

If a project uses Maven, then the way to specify the JVM compatibility is in the pom.xml ‘maven-compiler-plugin’ section.

<project>
 ...
 <build>
 ...
 <plugins>
   <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>3.7.0</version>
     <configuration>
       <source>1.7</source>
       <target>1.7</target>
     </configuration>
   </plugin>
 </plugins>

Alternatively, you can use the ‘maven.compiler.target’ in the <properties> element.

 

REFERENCES

https://stackoverflow.com/questions/1096148/how-to-check-the-jdk-version-used-to-compile-a-class-file (javap and JVM to major version map)

https://superuser.com/questions/706101/how-to-print-first-10-bytes-in-hexadecimal-of-a-file

https://en.wikipedia.org/wiki/Java_class_file#General_layout

http://www.draconianoverlord.com/2014/04/01/jdk-compatibility.html (even using target, Java 1.8 only classes can sneak in)

https://www.mkyong.com/maven/how-to-tell-maven-to-use-java-8/