What version of javac built my jar?

JavaJar

Java Problem Overview


How can I tell what version of the Java compiler was used to build a jar? I have a jar file, and it could have been built in any one of three JDKs. We need to know exactly which one, so we can certify compatibility. Is the compiler version embedded somewhere in the class files or jar?

Java Solutions


Solution 1 - Java

A jar is merely a container. It is a file archive ā la tar. While a jar may have interesting information contained within it's META-INF hierarchy, it has no obligation to specify the vintage of the classes within it's contents. For that, one must examine the class files therein.

As as Peter Lawrey mentioned in comment to the original question, you can't necessarily know which JDK release built a given class file, but you can find out the byte code class version of the class file contained in a jar.

Yes, this kinda sucks, but the first step is to extract one or more classes from the jar. For example:

$ jar xf log4j-1.2.15.jar

On Linux, Mac OS X or Windows with Cygwin installed, the file(1) command knows the class version.

$ file ./org/apache/log4j/Appender.class
./org/apache/log4j/Appender.class: compiled Java class data, version 45.3

Or alternatively, using javap from the JDK as @jikes.thunderbolt aptly points out:

$ javap -v ./org/apache/log4j/Appender.class | grep major
 major version: 45

For Windows environments without either file or grep

> javap -v ./org/apache/log4j/Appender.class | findstr major
 major version: 45

FWIW, I will concur that javap will tell a whole lot more about a given class file than the original question asked.

Anyway, a different class version, for example:

$ file ~/bin/classes/P.class
/home/dave/bin/classes/P.class: compiled Java class data, version 50.0

The class version major number corresponds to the following Java JDK versions:

  • 45.3 = Java 1.1

  • 46 = Java 1.2

  • 47 = Java 1.3

  • 48 = Java 1.4

  • 49 = Java 5

  • 50 = Java 6

  • 51 = Java 7

  • 52 = Java 8

  • 53 = Java 9

  • 54 = Java 10

  • 55 = Java 11

  • 56 = Java 12

  • 57 = Java 13

  • 58 = Java 14

Solution 2 - Java

You can't tell from the JAR file itself, necessarily.

Download a hex editor and open one of the class files inside the JAR and look at byte offsets 4 through 7. The version information is built in.

http://en.wikipedia.org/wiki/Java_class_file

Note: As mentioned in the comment below,

> those bytes tell you what version the class has been compiled FOR, not > what version compiled it.

Solution 3 - Java

Here is Java's way to find this information.

Windows: javap -v <class> | findstr major
Unix: javap -v <class> | grep major

For example:
> javap -v Application | findstr major   major version: 51

Solution 4 - Java

There is no need to unpack the JAR (if one of the class names is known or is looked up e.g. using 7zip), so on Windows the following would be sufficient:

javap -cp log4j-core-2.5.jar -verbose org.apache.logging.log4j.core.Logger | findstr major

Solution 5 - Java

The Java compiler (javac) does not build jars, it translates Java files into class files. The Jar tool (jar) creates the actual jars. If no custom manifest was specified, the default manifest will specify which version of the JDK was used to create the jar.

Solution 6 - Java

Since I needed to analyze fat jars I was interested in the version of each individual class in a jar file. Therefore I took Joe Liversedge approach https://stackoverflow.com/a/27877215/1497139 and combined it with David J. Liszewski' https://stackoverflow.com/a/3313839/1497139 class number version table to create a bash script jarv to show the versions of all class files in a jar file.

usage

usage: ./jarv jarfile
 -h|--help: show this usage

Example

jarv $Home/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar

java 1.4 org.apache.log4j.Appender
java 1.4 org.apache.log4j.AppenderSkeleton
java 1.4 org.apache.log4j.AsyncAppender$DiscardSummary
java 1.4 org.apache.log4j.AsyncAppender$Dispatcher
...

Bash script jarv

#!/bin/bash
# WF 2018-07-12
# find out the class versions with in jar file
# see https://stackoverflow.com/questions/3313532/what-version-of-javac-built-my-jar

# uncomment do debug
# set -x

#ansi colors
#http://www.csc.uvic.ca/~sae/seng265/fall04/tips/s265s047-tips/bash-using-colors.html
blue='\033[0;34m'  
red='\033[0;31m'  
green='\033[0;32m' # '\e[1;32m' is too bright for white bg.
endColor='\033[0m'

#
# a colored message 
#   params:
#     1: l_color - the color of the message
#     2: l_msg - the message to display
#
color_msg() {
  local l_color="$1"
  local l_msg="$2"
  echo -e "${l_color}$l_msg${endColor}"
}

#
# error
#
#   show an error message and exit
#
#   params:
#     1: l_msg - the message to display
error() {
  local l_msg="$1"
  # use ansi red for error
  color_msg $red "Error: $l_msg" 1>&2
  exit 1
}

#
# show the usage
#
usage() {
  echo "usage: $0 jarfile"
  # -h|--help|usage|show this usage
  echo " -h|--help: show this usage"
  exit 1 
}

#
# showclassversions
#
showclassversions() {
  local l_jar="$1"
  jar -tf "$l_jar" | grep '.class' | while read classname
  do
    class=$(echo $classname | sed -e 's/\.class$//')
    class_version=$(javap -classpath "$l_jar" -verbose $class | grep 'major version' | cut -f2 -d ":" | cut -c2-)
    class_pretty=$(echo $class | sed -e 's#/#.#g')
    case $class_version in
      45.3) java_version="java 1.1";;
      46) java_version="java 1.2";;
      47) java_version="java 1.3";;
      48) java_version="java 1.4";;
      49) java_version="java5";;
      50) java_version="java6";;
      51) java_version="java7";;
      52) java_version="java8";;
      53) java_version="java9";;
      54) java_version="java10";;
      *) java_version="x${class_version}x";;
    esac
    echo $java_version $class_pretty
  done
}

# check the number of parameters
if [ $# -lt 1 ]
then
  usage
fi

# start of script
# check arguments
while test $# -gt 0
do
  case $1 in
    # -h|--help|usage|show this usage
    -h|--help) 
      usage
      exit 1
      ;;
    *)
     showclassversions "$1"
  esac
  shift
done 

Solution 7 - Java

you can find Java compiler version from .class files using a Hex Editor.

Step 1: Extract .class files from jar file using a zip extractor

step 2: open .class file with a hex editor.(I have used notepad++ hex editor plugin. This plugin reads file as binary and shows it in hex) You can see below. enter image description here

Index 6 and 7 gives major version number of the class file format being used. https://en.wikipedia.org/wiki/Java_class_file

Java SE 11 = 55 (0x37 hex)

Java SE 10 = 54 (0x36 hex)

Java SE 9 = 53 (0x35 hex)

Java SE 8 = 52 (0x34 hex),

Java SE 7 = 51 (0x33 hex),

Java SE 6.0 = 50 (0x32 hex),

Java SE 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).

Solution 8 - Java

You can tell the Java binary version by inspecting the first 8 bytes (or using an app that can).

The compiler itself doesn't, to the best of my knowledge, insert any identifying signature. I can't spot such a thing in the file VM spec class format anyway.

Solution 9 - Java

The code posted by Owen can tell you the information mentioned by a number of the other answers here:

public void simpleExample ()
{
    FileInputStream fis = new FileInputStream ("mytest.class");
    parseJavaClassFile ( fis );
}
protected void parseJavaClassFile ( InputStream classByteStream ) throws Exception
{
    DataInputStream dataInputStream = new DataInputStream ( classByteStream );
    magicNumber = dataInputStream.readInt();
    if ( magicNumber == 0xCAFEBABE )
    {
        int minorVer = dataInputStream.readUnsignedShort();
        int majorVer = dataInputStream.readUnsignedShort();
        // do something here with major & minor numbers
    }
}

See also this and this site. I ended up modifying the Mind Products code quickly to check what each of my dependencies was compiled for.

Solution 10 - Java

Developers and administrators running Bash may find these convenience functions helpful:

jar_jdk_version() {
  [[ -n "$1" && -x "`command -v javap`" ]] && javap -classpath "$1" -verbose $(jar -tf "$1" | grep '.class' | head -n1 | sed -e 's/\.class$//') | grep 'major version' | sed -e 's/[^0-9]\{1,\}//'
}

print_jar_jdk_version() {
  local version
  version=$(jar_jdk_version "$1")
  case $version in 49) version=1.5;; 50) version=1.6;; 51) version=1.7;; 52) version=1.8;; esac
  [[ -n "$version" ]] && echo "`basename "$1"` contains classes compiled with JDK version $version."
}

You can paste them in for one-time usage or add them to ~/.bash_aliases or ~/.bashrc. The results look something like:

$ jar_jdk_version poi-ooxml-3.5-FINAL.jar
49

and

$ print_jar_jdk_version poi-ooxml-3.5-FINAL.jar
poi-ooxml-3.5-FINAL.jar contains classes compiled with JDK version 1.5.

EDIT As jackrabbit points out, you can't 100% rely on the manifest to tell you anything useful. If it was, then you could pull it out in your favorite UNIX shell with unzip:

$ unzip -pa poi-ooxml-3.5-FINAL.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 11.3-b02 (Sun Microsystems Inc.)
Built-By: yegor
Specification-Title: Apache POI
Specification-Version: 3.5-FINAL-20090928
Specification-Vendor: Apache
Implementation-Title: Apache POI
Implementation-Version: 3.5-FINAL-20090928
Implementation-Vendor: Apache

This .jar doesn't have anything useful in the manifest about the contained classes.

Solution 11 - Java

One liner (Linux)

unzip -p mylib.jar META-INF/MANIFEST.MF

This prints the content of MANIFEST.MF file to stdout (hopefully there is one in your jar file :)

Depending on what built your package, you will find the JDK version in Created-By or Build-Jdk key.

Solution 12 - Java

Each class file has a version number embedded for the byte code level which the JVM use to see if it likes that particular byte code chunk or not. This is 48 for Java 1.4, 49 for Java 1.5 and 50 for Java 6.

Many compilers exist which can generate byte code at each level, javac uses the "-target" option to indicate which byte code level to generate, and the Java 6 javac can generate byte code for at least 1.4, 1.5 and 6. I do not believe that the compiler inserts anything that can identify the compiler itself which is what I think you ask for. Also the Eclipse compiler is increasingly being used, as it is a single jar which can run with the JRE only.

In a jar file there is usually many classes, and each of them is independent, so you need to investigate all classes in the jar to be certain about the characteristics of the contents.

Solution 13 - Java

A good deal of times, you might be looking at whole jar files, or war files that contain many jar files in addition to themselves.

Because I didn't want to hand check each class, I wrote a java program to do that:

https://github.com/Nthalk/WhatJDK

./whatjdk some.war
some.war:WEB-INF/lib/xml-apis-1.4.01.jar contains classes compatible with Java1.1
some.war contains classes compatible with Java1.6

While this doesn't say what the class was compiled WITH, it determines what JDK's will be able to LOAD the classes, which is probably what you wanted to begin with.

Solution 14 - Java

You can easily do this on command line using following process :

If you know any of the class name in jar, you can use following command :

javap -cp jarname.jar -verbose packagename.classname | findstr major

example :

    C:\pathwherejarlocated> javap -cp jackson-databind-2.8.6.jar -verbose com.fasterxml.jackson.databind.JsonMappingException | findstr major

 

Output :

    major version: 51

Quick Reference :

JDK 1.0 — major version 45 
DK 1.1 — major version 45 
JDK 1.2 — major version 46 
JDK 1.3 — major version 47 
JDK 1.4 — major version 48 
JDK 1.5 — major version 49 
JDK 1.6 — major version 50 
JDK 1.7 — major version 51 
JDK 1.8 — major version 52 
JDK 1.9 — major version 53 

> PS : if you dont know any of the classname, you can easily do this by > using any of the jar decompilers or by simply using following command to extract jar file > : > > jar xf myFile.jar > >

Solution 15 - Java

IntelliJ Users
  • Install the plugin Archive Browser

https://i.stack.imgur.com/i4GaV.png" width="300" />

  • Open the Jar in Intellij. You can simply add the jar to any project by dragging and dropping the jar file from the file browser.

  • Browse through the jar file to locate a class file and the IntelliJ's decompiler should show the version of Java used to create the jar.

IntelliJ shows java version

Solution 16 - Java

Following up on @David J. Liszewski's answer, I ran the following commands to extract the jar file's manifest on Ubuntu:

# Determine the manifest file name:
$ jar tf LuceneSearch.jar | grep -i manifest
META-INF/MANIFEST.MF

# Extract the file:
$ sudo jar xf LuceneSearch.jar META-INF/MANIFEST.MF

# Print the file's contents:
$ more META-INF/MANIFEST.MF
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_25-b30 (Oracle Corporation)
Main-Class: org.wikimedia.lsearch.config.StartupManager

Solution 17 - Java

To expand on Jonathon Faust's and McDowell's answers: If you're on a *nix based system, you can use od (one of the earliest Unix programs1 which should be available practically everywhere) to query the .class file on a binary level:

od -An -j7 -N1 -t dC SomeClassFile.class

This will output the familiar integer values, e.g. 50 for Java 5, 51 for Java 6 and so on.

1 Quote from https://en.wikipedia.org/wiki/Od_(Unix)

Solution 18 - Java

I as well wrote my own bash script to dump the Java version required by all the jars passed at the command line... Mine is a bit rough, but works for me ;-)

example usage
$ jar_dump_version_of_jvm_required.sh *.jar
JVM VERSION REQUIRED: 46.0, /private/tmp/jars/WEB-INF/lib/json-simple-1.1.jar
JVM VERSION REQUIRED: 49.0, /private/tmp/jars/WEB-INF/lib/json-smart-1.1.1.jar
JVM VERSION REQUIRED: 50.0, /private/tmp/jars/WEB-INF/lib/jsontoken-1.0.jar
JVM VERSION REQUIRED: 50.0, /private/tmp/jars/WEB-INF/lib/jsr166y-1.7.0.jar

###jar_dump_version_of_jvm_required.sh

#!/bin/bash

DIR=$(PWD)
function show_help()
{
  ME=$(basename $0)
  IT=$(cat <<EOF
  
  Dumps the version of the JVM required to run the classes in a jar file

  usage: $ME JAR_FILE
  
  e.g. 
  
  $ME myFile.jar    ->  VERSION: 50.0     myFile.jar

  Java versions are:
  54 = Java 10
  53 = Java 9
  52 = Java 8
  51 = Java 7
  50 = Java 6
  49 = Java 5
  48 = Java 1.4
  47 = Java 1.3
  46 = Java 1.2
  45.3 = Java 1.1

EOF
  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

function unzipJarToTmp()
{
  JAR=$1
  CLASS_FILE=$(jar -tf "$JAR" | grep \.class$ | grep -v '\$' | head -n1 | awk '{print $NF}')
  OUT_FILE="$CLASS_FILE"
  #echo "J=$JAR C=$CLASS_FILE O=$OUT_FILE"
  jar xf "$JAR" "$CLASS_FILE"

  MAJOR=$(javap -v "$OUT_FILE" 2>&1 | grep major | awk -F' ' '{print $3'})
  MINOR=$(javap -v "$OUT_FILE" 2>&1 | grep minor | awk -F' ' '{print $3'})
  if [ -z "$MAJOR" ]
  then
    echo "JVM VERSION REQUIRED: NA as no classes in $JAR"
  else
    echo "JVM VERSION REQUIRED: $MAJOR.$MINOR, $JAR"
  fi
}

# loop over cmd line args
for JAR in "$@"
do
  cd "$DIR"
  JAR_UID=$(basename "$JAR" | sed s/.jar//g)
  TMPDIR=/tmp/jar_dump/$JAR_UID/
  mkdir -p "$TMPDIR"
  JAR_ABS_PATH=$(realpath $JAR)

  cd "$TMPDIR"

  #echo "$JAR_ABS_PATH"
  unzipJarToTmp "$JAR_ABS_PATH"
  #sleep 2
done

Solution 19 - Java

You check in Manifest file of jar example:

Manifest-Version: 1.0 Created-By: 1.6.0 (IBM Corporation)

Solution 20 - Java

On Windows do the following:

  1. Unzip or extract the JAR file using WinZip / Java JAR command.
  2. Drag and Drop one of the class files into your Eclipse Java project.
  3. Open the class file.

Now Eclipse will show the exact major and minor version.

Solution 21 - Java

I build a little bash script (on github) based on Davids suggestion using the file command

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRon RomeroView Question on Stackoverflow
Solution 1 - JavaDavid J. LiszewskiView Answer on Stackoverflow
Solution 2 - JavaJonathon FaustView Answer on Stackoverflow
Solution 3 - Javajikes.thunderboltView Answer on Stackoverflow
Solution 4 - JavaanreView Answer on Stackoverflow
Solution 5 - JavajackrabbitView Answer on Stackoverflow
Solution 6 - JavaWolfgang FahlView Answer on Stackoverflow
Solution 7 - Javacahit beyazView Answer on Stackoverflow
Solution 8 - JavaMcDowellView Answer on Stackoverflow
Solution 9 - JavaJasonPlutextView Answer on Stackoverflow
Solution 10 - JavaJoe LiversedgeView Answer on Stackoverflow
Solution 11 - JavaNeal XiongView Answer on Stackoverflow
Solution 12 - JavaThorbjørn Ravn AndersenView Answer on Stackoverflow
Solution 13 - JavaNthalkView Answer on Stackoverflow
Solution 14 - JavaShwetaView Answer on Stackoverflow
Solution 15 - JavaAditya Vikas DevarapalliView Answer on Stackoverflow
Solution 16 - JavaAlanView Answer on Stackoverflow
Solution 17 - Javazb226View Answer on Stackoverflow
Solution 18 - JavaBrad ParksView Answer on Stackoverflow
Solution 19 - Javaamoljdv06View Answer on Stackoverflow
Solution 20 - JavaKittuView Answer on Stackoverflow
Solution 21 - JavabeardedN5rdView Answer on Stackoverflow