2010-07-22 18 views
155

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

+6

Usted puede decir la mayor Verson mirando el archivo de manifiesto. Puede decir la versión de destino mirando los archivos de clase, pero los JDK pueden producir archivos de clase para versiones anteriores de Java utilizando la opción -target, por lo que mirar los primeros bytes puede no ser preciso. –

+8

En MANIFEST.MF puede encontrar algo como 'Created-By: 1.7.0_13 (Oracle Corporation)' – hko19

+0

Parece que Maven 3 hace esto 'Created-By: Apache Maven' y' Build-Jdk: 1.8.0_25' –

Respuesta

71

No se puede decir desde el archivo JAR, necesariamente.

descargar un editor hexadecimal y abrir uno de los archivos de clase dentro de la jarra y mirar desplazamientos de bytes 4 a 7. Se construyó la información de versión en

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

. Nota: Como se ha mencionado en el comentario a continuación,

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

+32

Para ser pedante, esos bytes te dicen para qué versión se ha compilado la clase, no qué versión compilada. Java le permite compilar código para que sea compatible con versiones anteriores de Java. Sin embargo, esto solo se aplica al código de bytes y al formato. Felizmente compilará código que hace referencia a bibliotecas JDK 6 en un formato JDK 5, por ejemplo. El JDK 5 cargará la clase, pero no puede ejecutarla ya que la biblioteca JDK 5 no tiene el código al que se hace referencia desde JDK 6. –

+3

Podríamos encontrarlo en el archivo de manifiesto como Creado por: 1.7.0_21-b11 (Oracle Corporation) – Krishna

+7

** [La otra respuesta] (http://stackoverflow.com/a/3313839/641451) le dice cómo hacer una fácil verificación a través de la línea de comando ** – mgarciaisaia

9

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

+1

Si bien es cierto, esto no proporciona una respuesta a la pregunta. – zb226

+0

@ zb226 AFAIK la versión del compilador utilizado para compilar las clases no puede obtenerse de los archivos de clase, solo la versión que las clases fueron compiladas _for_. La información que proporcioné proporciona la única información (estándar) que está disponible sobre la versión que construyó el artefacto. Si eso no es lo que se pregunta, la pregunta debe reformularse. – jackrabbit

+0

OK, estaba viendo eso desde un punto de vista pragmático, pero veo tu punto ahora, se eliminó el voto negativo :) – zb226

2

Cada archivo de clase tiene un número de versión incrustado para el nivel de código de bytes que la JVM usa para ver si le gusta ese fragmento de código de bytes 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 que pueda identificar al compilador, que es lo que creo que usted solicita. Además, cada vez se utiliza más el compilador Eclipse, ya que se trata de un único contenedor que solo se puede ejecutar con 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 contenedor para asegurarse de las características de los contenidos.

243

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 obligación de especificar la antigüedad de las clases dentro de sus contenidos. Para eso, uno debe examinar los archivos class en el mismo.

Como como Peter Lawrey mencionados en el comentario a la pregunta original, no necesariamente puede saber qué versión del JDK construyó una class archivo determinado, pero se puede averiguar la versión de la clase de código de bytes del archivo class contenida en un jar.

Sí, esto es una mierda, pero el primer paso es extraer una o más clases del 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, utilizando javap desde el JDK como @ jikes.thunderbolt acertadamente señala:

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

Y si son relegados a un medio ambiente sin que ninguna de Windowsfile o grep

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

FWIW, coincidiré en que javap contará mucho más sobre undadoarchivo que la pregunta original.

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 

La versión de la clase mayor número corresponde a las siguientes versiones 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
+6

Mi versión de 'archivo' no lo mostró, pero pude verificar la clase manualmente con este comando: 'hexdump ~/bin/classes/P.class | cabeza'. Solo mira el octavo byte y conviértete en decimal. –

+2

FYI 'archivo' parece depender de la versión de Java en cuanto a si también mostrará la versión JDK. en CentOS/Oracle Linux y una clase Java compilado 6 consigo "datos compilados de clase Java, versión 50.0 (Java 1.6)" pero cuando lo ejecuto en una clase compilada con Java 7 Acabo de obtener la versión genérica "datos compilados de la clase Java, versión 51.0" –

+0

'' JAR = something.jar; descomprimir -p $ JAR 'unzip -l $ JAR | grep '\ .class $' | cabeza -1' | file -'' –

5

El code posted by Owen puede indicarle la información mencionada por una número 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 
    } 
} 

Véase también this y this sitio. Terminé modificando el código de Mind Products rápidamente para verificar para qué se compilaba cada una de mis dependencias.

2

El seguimiento de la respuesta de @ David J. Liszewski, me encontré con 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 
+2

O, como una línea: 'descomprime -p LiceneSearch.jar META-INF/MANIFEST.MF' –

0

En Windows haga lo siguiente:

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

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

40

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

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

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

+2

de todas las respuestas dadas, tu respuesta es la más concisa y no implica escribir 10 líneas de código para conocer la versión información. +1 para eso –

+1

¿Para qué sirve el parámetro ''? – Dims

+1

@Dims El archivo ".class" que está tratando de encontrar la versión de. En su ejemplo, tiene un archivo 'Application.class' y resultó ser compilado para Java 7 (' versión principal: 51'). – inanutshellus

3

Los desarrolladores y administradores que ejecutan Bash pueden encontrar estas funciones de confort votos:

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 pegar para el uso de una sola vez o agregar a ~/.bash_aliases o ~/.bashrc. Los resultados parecen 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 puntos cabo, no se puede confiar 100% en el manifiesto que le diga algo útil. Si lo fuera, entonces se podría tirar de él hacia fuera en su favorito de shell UNIX 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 

Este .jar no tiene nada útil en el manifiesto de las clases contenidas.

0

construyo un poco de escritura del golpe (on github) basado en la sugerencia Davids con el comando file

4

Un forro (Linux)

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

Esto imprime el contenido de MANIFEST.MF archivo a la salida estándar (esperemos que no existe uno en su archivo jar :)

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

+2

Tenga en cuenta que no hay obligación de que estos campos estén presentes en 'MANIFEST.MF', así como que no hay obligación de que los valores sean correctos (Sí, una vez encontré un' .jar' donde el valor era falso). – zb226

0

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

Debido a que no quería comprobar 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 lo que la clase fue compilado con, determina qué JDK podrá cargar las clases, que es probablemente con lo que quería comenzar.

7

No es necesario desempaquetar el JAR (si uno de los nombres de clase se conoce o se busca, p.usando 7zip), por lo que en Windows la siguiente sería suficiente:

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

Esto también funciona en Linux (excepto que usaría grep en lugar de findstr, por supuesto) –

2

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

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

Esta es la salida de los valores enteros conocidos, por ejemplo, 50 para Java 5, 51 para Java 6 y así sucesivamente.

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

Cuestiones relacionadas