我如何知道哪个版本的Java编译器被用来构建一个jar?我有一个jar文件,它可以构建在三个jdk中的任何一个中。我们需要确切知道是哪一个,这样我们才能证明兼容性。编译器版本是否嵌入到类文件或jar中?


当前回答

Owen发布的代码可以告诉你一些其他答案中提到的信息:

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代码,以检查我的每个依赖项是为了什么而编译的。

其他回答

很多时候,您可能会查看整个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

虽然这并没有说明类是用什么编译的,但它决定了哪些JDK能够加载这些类,这可能是您想要开始的。

不需要解包JAR(如果其中一个类名已知或被查找,例如使用7zip),因此在Windows上,以下步骤就足够了:

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

基于现有的答案,我试图构建一些更方便的东西,应该在大多数操作系统上工作(这取决于cat, xxd和awk),你只需要把你的类文件名从你的jar中提取出来。

cat YOUR_FILE.class | xxd -s 7 -l1 | awk  '{print $2}' | sed -e 's/34/Java SE 8/' -e 's/35/Java SE 9/' -e 's/36/Java SE 10/' -e 's/37/Java SE 11/' -e 's/38/Java SE 12/' -e 's/39/Java SE 13/' -e 's/3a/Java SE 14/' -e 's/3b/Java SE 15/' -e 's/3c/Java SE 16/' -e 's/3d/Java SE 17/' -e 's/3e/Java SE 18/'

方便的映射到人类可读的版本适用于Java 8开始的主要版本。(否则你会得到主版本的普通十六进制版本号,参见1中的链接。对于一个定义)

这个小脚本是基于什么:

我使用类文件的内容,并使用xxd获取第7个字节。 根据定义,这是用于主要版本的,参见维基百科: https://en.wikipedia.org/wiki/Java_class_file 然后我只是用一个列表代替所有版本值开始的十六进制34 java 8和结束的十六进制3e java 18。

运行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

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.

编辑 正如jackrabbit指出的那样,你不能100%依赖舱单告诉你任何有用的东西。如果是,那么你可以在你最喜欢的UNIX shell中使用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在清单中没有任何关于所包含类的有用信息。

一行程序(Linux)

解压-p mylib.jar META-INF/MANIFEST. jar曼氏金融

这将打印MANIFEST的内容。MF文件转换为stdout(希望你的jar文件中有一个:)

根据构建包的方式,您将在“Created-By”或“Build-Jdk”键中找到JDK版本。