¿Qué versión de javac construyó mi jar?


¿Cómo puedo saber qué versión del compilador Java se utilizó para construir un jar? Tengo un archivo jar, y podría haber sido construido en cualquiera de los tres JDKs. Necesitamos saber exactamente cuál, para poder certificar la compatibilidad. ¿La versión del compilador está incrustada en algún lugar de los archivos de clase o jar?

 173
Author: Tshepang, 2010-07-23

18 answers

No se puede decir desde el archivo JAR en sí, necesariamente.

Descargue un editor hexadecimal y abra uno de los archivos de clase dentro del JAR y mire las compensaciones de bytes del 4 al 7. La información de la versión está incorporada.

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

Nota: Como se menciona en el comentario a continuación,

Esos bytes le dicen para qué versión se ha compilado la clase, no qué versión lo compiló.

 78
Author: Jonathon Faust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-21 12:37:46

A jar es simplemente un contenedor. Es un archivo de archivo ā la tar. Mientras que un jar puede tener información interesante contenida dentro de su jerarquía META-INF, no tiene la obligación de especificar la vendimia de las clases dentro de su contenido. Para eso, uno debe examinar los archivos class allí.

Al igual que Peter Lawrey mencionado en el comentario a la pregunta original, no necesariamente puede saber qué versión JDK construyó un archivo class dado, pero puede encontrar fuera de la versión de la clase de código de bytes del archivo class contenido en un jar.

Sí, esto apesta un poco, pero el primer paso es extraer una o más clases de jar. Por ejemplo:

$ jar xf log4j-1.2.15.jar

En Linux, Mac OS X o Windows con Cygwin instalado, el comando file(1) conoce la versión de la clase.

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

O alternativamente, usando javap del JDK como @jikes.thunderbolt señala acertadamente:

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

Y si estás relegado a un {[14]]} medio ambiente sin file o grep

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

FWIW, estoy de acuerdo en que javap dirá mucho más sobre un archivo class dado que la pregunta original hecha.

De todos modos, una versión de clase diferente, por ejemplo:

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

El número mayor de la versión de la clase corresponde a las siguientes versiones de 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
 273
Author: David J. Liszewski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-12 14:55:18

Aquí está la manera de Java de encontrar esta información.

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

Por ejemplo:
> javap -v Application | findstr major   major version: 51

 43
Author: jikes.thunderbolt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-20 18:33:34

El compilador Java (javac) no construye jars, sino que traduce archivos Java en archivos de clase. La herramienta Jar (jar) crea los jars reales. Si no se especificó ningún manifiesto personalizado, el manifiesto predeterminado especificará qué versión del JDK se utilizó para crear el jar.

 12
Author: jackrabbit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-09 15:02:31

No hay necesidad de desempaquetar el JAR (si se conoce uno de los nombres de clase o se busca, por ejemplo, usando 7zip), por lo que en Windows lo siguiente sería suficiente:

javap -cp log4j-core-2.5.jar -verbose org.apache.logging.log4j.core.Logger | findstr major
 9
Author: anre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-08 18:30:34

Puedes saber la versión binaria de Java inspeccionando los primeros 8 bytes (o usando una aplicación que pueda hacerlo).

El compilador en sí no inserta, a mi leal saber y entender, ninguna firma identificativa. No puedo detectar tal cosa en el archivo VM spec class format de todos modos.

 4
Author: McDowell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 21:19:11

El código publicado por Owen puede decirle la información mencionada por varias de las otras respuestas aquí:

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

Ver también este y este sitio. Terminé modificando el código de Mind Products rápidamente para verificar para qué se compiló cada una de mis dependencias.

 4
Author: JasonPlutext,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-20 19:36:06

Un liner (Linux)

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

Esto imprime el contenido del archivo MANIFEST.MF a stdout (esperemos que haya uno en su archivo jar:)

Dependiendo de lo que construyó su paquete, encontrará la versión JDK en la clave Created-By o Build-Jdk.

 3
Author: Neal Xiong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-14 19:44:48

Cada archivo de clase tiene un número de versión incrustado para el nivel de código de byte que la JVM utiliza para ver si le gusta ese fragmento de código de byte en particular o no. Esto es 48 para Java 1.4, 49 para Java 1.5 y 50 para Java 6.

Existen muchos compiladores que pueden generar código de bytes en cada nivel, javac usa la opción "-target" para indicar qué nivel de código de bytes generar, y Java 6 javac puede generar código de bytes para al menos 1.4, 1.5 y 6. No creo que el compilador inserte nada eso puede identificar el compilador en sí, que es lo que creo que usted pide. También el compilador Eclipse se está utilizando cada vez más, ya que es un solo jar que puede ejecutarse solo con el JRE.

En un archivo jar generalmente hay muchas clases, y cada una de ellas es independiente, por lo que debe investigar todas las clases en el jar para estar seguro de las características del contenido.

 2
Author: Thorbjørn Ravn Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 21:51:44

Los desarrolladores y administradores que ejecutan Bash pueden encontrar útiles estas funciones de conveniencia:

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

Puede pegarlos para un uso único o agregarlos a ~/.bash_aliases o ~/.bashrc. Los resultados se ven algo así como:

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

Y

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

EDITAR Como jackrabbit señala, no puedes confiar al 100% en el manifiesto para decirte algo útil. Si lo fuera, entonces podría extraerlo en su shell UNIX favorito con 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

Esto .jar no tiene cualquier cosa útil en el manifiesto sobre las clases contenidas.

 2
Author: Joe Liversedge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:47

Siguiendo la respuesta de @David J. Liszewski, ejecuté los siguientes comandos para extraer el manifiesto del archivo jar en 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
 1
Author: Alan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-21 05:26:39

Muchas veces, es posible que esté buscando archivos jar completos, o archivos war que contienen muchos archivos jar además de ellos mismos.

Como no quería revisar a mano cada clase, escribí un programa Java para hacer eso:

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

Si bien esto no dice con qué se compiló la clase, determina con qué JDK podrá CARGAR las clases, que es probablemente con lo que quería comenzar.

 1
Author: Nthalk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-29 05:04:47

Para ampliar las respuestas de Jonathon Faust y de McDowell : Si estás en un sistema basado en * nix, puedes usar od (uno de los primeros programas Unix1 que debería estar disponible prácticamente en todas partes) para consultar el archivo .class a nivel binario:

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

Esto generará los valores enteros familiares, por ejemplo, 50 para Java 5, 51 para Java 6 y así sucesivamente.

1 Cita de https://en.wikipedia.org/wiki/Od_(Unix)

 1
Author: zb226,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-28 20:11:32

Dado que necesitaba analizar los frascos de grasa, estaba interesado en la versión de cada clase individual en un archivo jar. Por lo tanto tomé Joe Liversedge enfoque https://stackoverflow.com/a/27877215/1497139 y lo combinó con David J. Liszewski ' https://stackoverflow.com/a/3313839/1497139 número de clase tabla de versiones para crear un script bash jarv para mostrar las versiones de todos los archivos de clase en un jar file.

Uso

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

Ejemplo

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 
 1
Author: Wolfgang Fahl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-12 09:58:03

Usted comprueba en el archivo de manifiesto de jar ejemplo:

Manifest-Versión: 1.0 Creado por: 1.6.0 (IBM Corporation)

 0
Author: amoljdv06,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-22 09:54:13

Puede encontrar la versión del compilador de Java.archivos de clase usando un Editor hexadecimal.

Paso 1: Extraer .archivos de clase del archivo jar usando un extractor zip

Paso 2: abrir .archivo de clase con un editor hexadecimal.(He utilizado notepad++ hex editor plugin. Este plugin lee el archivo como binario y lo muestra en hexadecimal) Se puede ver a continuación. introduzca la descripción de la imagen aquí

El índice 6 y 7 da el número de versión principal del formato de archivo de clase siendo utilizar. 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).

 0
Author: cahit beyaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-27 14:00:01

En Windows haga lo siguiente:

  1. Descomprima o extraiga el archivo JAR usando el comando WinZip / Java JAR.
  2. Arrastre y suelte uno de los archivos de clase en su proyecto Java de Eclipse.
  3. Abra el archivo de clase.

Ahora Eclipse mostrará la versión mayor y menor exacta.

 -1
Author: Kittu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-20 19:15:12

Construyo un pequeño script bash (en github) basado en la sugerencia de Davids usando el comando file

 -1
Author: beardedN5rd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-20 18:09:36