What version of javac built my jar?

前端 未结 20 782
孤街浪徒
孤街浪徒 2020-11-27 09:48

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

相关标签:
20条回答
  • 2020-11-27 10:23

    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.

    0 讨论(0)
  • 2020-11-27 10:28

    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 
    
    0 讨论(0)
  • 2020-11-27 10:29

    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
    
    0 讨论(0)
  • 2020-11-27 10:30

    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
    
    0 讨论(0)
  • 2020-11-27 10:32

    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)

    0 讨论(0)
  • 2020-11-27 10:36

    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.

    0 讨论(0)
提交回复
热议问题