どのバージョンのjavacが私のjarをビルドしましたか?


212

jarのビルドに使用されたJavaコンパイラのバージョンを確認するにはどうすればよいですか?私はjarファイルを持っています。それは3つのJDKのいずれかに組み込まれている可能性があります。どちらが正しいかを知る必要があるため、互換性を証明できます。コンパイラのバージョンはクラスファイルまたはjarのどこかに埋め込まれていますか?


8
マニフェストファイルを見ると、メジャーバージョンを確認できます。クラスファイル自体を調べることでターゲットバージョンを確認できますが、JDKは-targetオプションを使用して以前のバージョンのJava用のクラスファイルを生成できるため、最初のバイトを調べるのは正確ではない場合があります。
— Peter Lawrey 2010

15
MANIFEST.MFでは、次のようなものを見つけることができますCreated-By: 1.7.0_13 (Oracle Corporation)
— hko19

1
Maven 3がこれCreated-By: Apache Mavenを行うように見えますBuild-Jdk: 1.8.0_25
— Neal Xiong

これを確認してください:stackoverflow.com/questions/27065/…–
— Abheek Dutta 2017

回答:


89

必ずしもJARファイル自体からは判別できません。

16進エディタをダウンロードし、JAR内のクラスファイルの1つを開いて、バイトオフセット4〜7を確認します。バージョン情報が組み込まれています。

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

注:以下のコメントで述べたように、

それらのバイトは、クラスがどのバージョンでコンパイルされたかではなく、どのバージョンでコンパイルされたかを示します。


41
わかりやすくするために、これらのバイトは、クラスがコンパイルされたバージョンではなく、コンパイルされたバージョンを示します。Javaを使用すると、以前のバージョンのJavaと互換性を持つようにコードをコンパイルできます。ただし、これはバイトコードとフォーマットにのみ適用されます。たとえば、JDK 6ライブラリを参照するコードをJDK 5形式にコンパイルします。JDK 5は、クラスをロードしますが、JDK 5ライブラリはJDK 6から参照コード持っていないとして、それを実行することはできません
— ウィル・アルトゥング

6
マニフェストファイルでCreated-By:1.7.0_21-b11(Oracle Corporation)
— Krishna

8
もう1つの回答は、コマンドラインで簡単に確認する方法を示しています
— mgarciaisaia 2014年

313

A jarは単なるコンテナーです。これはファイルアーカイブāla tarです。にはMETA-INF階層jar内に興味深い情報が含まれている場合がありますが、そのコンテンツ内のクラスのヴィンテージを指定する義務はありません。そのためには、その中のファイルを調べる必要があります。class

以下のようにピーターLawreyは、元の質問にコメントで述べたように、あなたは、必ずしも特定の内蔵されているJDKのリリースを知ることができないclassファイルを、しかし、あなたはのバイトコードクラスバージョンを見つけることができますclassに含まれるファイルをjar。

はい、これはひどいですが、最初のステップはから1つ以上のクラスを抽出することjarです。例えば:

$ jar xf log4j-1.2.15.jar

CygwinがインストールされているLinux、Mac OS X、またはWindows では、file(1)コマンドはクラスのバージョンを認識しています。

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

あるいは、javap@ jikes.thunderboltが適切に指摘するようにJDKから使用すること:

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

そして、あなたはに追いやられている場合Windowsせずに環境のいずれかfileまたはgrep

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

FWIW、私はそれjavapが与えられたclassファイルについて、元の質問が尋ねたよりもずっと多くのことを伝えることに同意します。

とにかく、別のクラスバージョン、たとえば:

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

クラスバージョンのメジャー番号は、次のJava JDKバージョンに対応しています。

  • 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

7
のバージョンでfileは表示されませんでしたが、次のコマンドを使用して手動でクラスを確認できました:hexdump ~/bin/classes/P.class | head。8バイト目を見て、10進数に変換します。
— Jarett Millard 2013

2
FYI「ファイル」は、JDKバージョンも表示するかどうかについて、Javaバージョンに依存しているようです。CentOS / Oracle LinuxとJava 6コンパイル済みクラスでは、「コンパイル済みJavaクラスデータ、バージョン50.0(Java 1.6)」が表示されますが、Java 7でコンパイルされたクラスで実行すると、汎用バージョンの「コンパイル済みJavaクラスデータ、バージョン51.0 "
— Dan Haynes

1
JAR=something.jar ; unzip -p $JAR `unzip -l $JAR | grep '\.class$' | head -1` | file -
— ランドールホイットマン、

3
@JarettMillard私のcygwin file file.class(5.22-1)は最初にJavaクラスターゲットを表示しませんでした: "file.class:[architecture = 6909806] [architecture = 6845039]"。ただしfile -k file.class、「file.class:[architecture = 6909806] [architecture = 6845039]コンパイル済みJavaクラスデータ、バージョン50.0(Java 1.6)」でした。fileなしのmagicfiles dbで最初に一致したものだけのよう-kです。
— 2015

1
「javap -p <class> | grep major」の使用は信頼できません。pom.xmlのソース/ターゲットが1.7の場合、コンパイルにJDK 1.7、JDK 1.8、またはJDK 1.9のどちらを使用するかに関係なく、javapは常に「メジャーバージョン:51」を提供します。
— user2569618

54

この情報を見つけるためのJavaの方法を次に示します。

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

例えば:
> javap -v Application | findstr major   major version: 51


3
与えられたすべての答えのうち、あなたの答えは最も簡潔であり、バージョン情報を知るために10行のコードを書く必要はありません。そのための+1
— ティルマライパルタサラティ

2
何である<class>のパラメータは?
— DIMS

1
@Dimsバージョンを見つけようとしている「.class」ファイル。彼の例では、彼はApplication.classファイルを持っていて、Java 7用にコンパイルされていることがわかりました(major version: 51)。
— inanutshellus

1
これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

15

JARを解凍する必要はありません(クラス名の1つが既知であるか、たとえば7zipを使用して検索されている場合)ので、Windowsでは以下で十分です。

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

1
これはLinuxでも機能します(もちろん、findstrの代わりにgrepを使用する場合を除きます)
— Michael Rusch

1
これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

15

Javaコンパイラ(javac)はjarを構築せず、Javaファイルをクラスファイルに変換します。jarjar ツール()は実際のjarを作成します。カスタムマニフェストが指定されていない場合、デフォルトのマニフェストは、jarの作成に使用されたJDKのバージョンを指定します。


3
これは真実ですが、質問に対する答えを提供しません。
— zb226 2017年

2
@ zb226 AFAIKクラスのコンパイルに使用されたコンパイラのバージョンは、クラスファイルから取得できません。クラスがコンパイルされたバージョンのみを取得できます。私が提供した情報は、アーティファクトを構築したバージョンについて入手できる唯一の(標準)情報を提供します。それが求められていることではない場合は、質問を書き直す必要があります。
— jackrabbit 2017年

わかりました、私は実用的な観点からそれを見ていましたが、私はあなたの主張を今見ています、反対投票は削除されました:)
— zb226

9

太いjarを分析する必要があったので、jarファイルの個々のクラスのバージョンに興味がありました。したがって、Joe Liversedgeのアプローチhttps://stackoverflow.com/a/27877215/1497139を採用 し、David J. Liszewskiのhttps://stackoverflow.com/a/3313839/1497139クラス番号バージョンテーブルと組み合わせて、bashスクリプトを作成しましたjarvは、jarファイル内のすべてのクラスファイルのバージョンを表示します。

使用法

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

例

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スクリプト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 

1
素晴らしいスクリプト!jarのJavaバージョンを確認できました。
— アーク

スクリプトを共有していただき、誠にありがとうございます。私の側からのほんのヒント。head -1スクリプトと組み合わせて使用​​できます。通常、jarファイルの最初のクラスのバージョンを確認するだけで十分です。
— Sergey Brunov

7

16進エディタを使用して、.classファイルからJavaコンパイラのバージョンを見つけることができます。

ステップ1:zipエクストラクターを使用してjarファイルから.classファイルを抽出する

手順2:hexエディターで.classファイルを開きます(私はnotepad ++ hexエディタープラグインを使用しました。このプラグインはファイルをバイナリとして読み取り、16進数で表示します)。 ここに画像の説明を入力してください

インデックス6および7は、使用されているクラスファイル形式のメジャーバージョン番号を示しています。 https://en.wikipedia.org/wiki/Java_class_file

Java SE 11 = 55(16進数で0x37)

Java SE 10 = 54(16進数で0x36)

Java SE 9 = 53(16進数で0x35)

Java SE 8 = 52(16進数で0x34)、

Java SE 7 = 51(16進数で0x33)、

Java SE 6.0 = 50(16進数で0x32)、

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)。


4

最初の8バイトを調べる(またはできるアプリを使用する)ことで、Javaバイナリバージョンを確認できます。

コンパイラ自体は、私の知る限りでは、識別用の署名を挿入しません。とにかく、ファイルVMスペッククラス形式でそのようなことを見つけることはできません。


これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

4

オーウェンによって掲示コードはあなたにここで他の回答の数で言及した情報を伝えることができます。

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
    }
}

これとこのサイトも参照してください。Mind Productsコードをすばやく変更して、各依存関係のコンパイル対象を確認しました。


これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

3

Bashを実行している開発者と管理者は、次の便利な機能が役立つと感じる場合があります。

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."
}

あなたのワンタイム使用のためにそれらを貼り付けたり、それらを追加することができます~/.bash_aliasesか~/.bashrc。結果は次のようになります。

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

そして

$ 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 としてJackrabbitのは指摘する、あなたは100%はあなたに有益な何かを伝えるためにマニフェストに頼ることはできません。もしそうなら、あなたはあなたのお気に入りのUNIXシェルでそれを引き出すことができます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

この.jarには、含まれるクラスに関するマニフェストで役立つものは何もありません。


これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

3

ワンライナー(Linux)

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

これにより、MANIFEST.MFファイルの内容が標準出力に出力されます(jarファイルに1つあることを願います)。

パッケージのビルド内容に応じて、JDKのバージョンCreated-ByまたはBuild-Jdkキーが見つかります。


3
これらのフィールドがに存在するMANIFEST.MF義務はなく、値が正しいことも義務ではないことに注意してください(はい、.jar値が偽の場所に出会ったことがあります)。
— zb226 2017年

これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

2

各クラスファイルには、JVMが特定のバイトコードチャンクが好きかどうかを確認するために使用するバイトコードレベルのバージョン番号が埋め込まれています。これは、Java 1.4では48、Java 1.5では49、Java 6では50です。

各レベルでバイトコードを生成できる多くのコンパイラが存在し、javacは「-target」オプションを使用してどのバイトコードレベルを生成するかを示し、Java 6 javacは少なくとも1.4、1.5、6のバイトコードを生成できます。コンパイラーは、コンパイラー自体を識別できるものを挿入すると信じています。また、JREでのみ実行できる単一のjarであるため、Eclipseコンパイラーの使用が増加しています。

jarファイルには通常多くのクラスがあり、それぞれが独立しているため、jar内のすべてのクラスを調査して、内容の特性を確認する必要があります。


1

@David J. Liszewskiの回答に続き、次のコマンドを実行してUbuntuでjarファイルのマニフェストを抽出しました。

# 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

2
または、ワンライナーとして:unzip -p LiceneSearch.jar META-INF/MANIFEST.MF
— Ogre Psalm33

これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

1

多くの場合、jarファイル全体、または自分自身に加えて多くのjarファイルを含むwarファイルを表示している可能性があります。

各クラスを手動でチェックしたくなかったので、それを行うJavaプログラムを作成しました。

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

これは、クラスがWITHでコンパイルされたものを示していませんが、クラスをロードできるJDKを決定します。


1

展開するにはジョナサン・ファウストさんとマクダウェルの答え:あなたは* nixのベースのシステムを使っている場合は、使用することができますod(最も初期のUnixのプログラムの一つ1照会することは事実上どこでも利用可能であるべきである).class、バイナリレベルでのファイルを:

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

これは、おなじみの整数値、たとえば50for Java 5、51for Java 6などを出力します。

1 https://en.wikipedia.org/wiki/Od_(Unix)からの引用


これらのコマンドjavacは、要求された.classファイルをコンパイルしたバージョンではなく、ターゲットJVMバージョンを提供します。
— ローン侯爵

1

コマンドラインで渡されたすべてのjarに必要なJavaバージョンをダンプするために、独自のbashスクリプトも作成しました...鉱山はやや荒れていますが、私にとってはうまくいきます;-)

使用例

$ 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

1

これは、次のプロセスを使用してコマンドラインで簡単に実行できます。

jarのクラス名がわかっている場合は、次のコマンドを使用できます。

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

例:

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

出力:

    major version: 51

クイックリファレンス :

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:クラス名がわからない場合は、jar逆コンパイラのいずれかを使用するか、次のコマンドを使用してjarファイルを抽出するだけで簡単にこれを行うことができます。

jar xf myFile.jar

0

あなたはjarの例のマ​​ニフェストファイルをチェックインします:

マニフェストバージョン:1.0作成者:1.6.0(IBM Corporation)


-1

Windowsでは、次のようにします。

  1. WinZip / Java JARコマンドを使用してJARファイルを解凍または抽出します。
  2. クラスファイルの1つをEclipse Javaプロジェクトにドラッグアンドドロップします。
  3. クラスファイルを開きます。

これで、Eclipseは正確なメジャーバージョンとマイナーバージョンを表示します。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.