javac example
¿Qué versión de javac construyó mi jar? (16)
¿Cómo puedo saber qué versión del compilador de Java se utilizó para construir un jar? 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?
Aquí está la forma de Java de encontrar esta información.
Windows: javap -v <class> | findstr major
javap -v <class> | findstr major
Unix: javap -v <class> | grep major
javap -v <class> | grep major
Por ejemplo:
> javap -v Application | findstr major major version: 51
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 lo hago Creo que el compilador inserta todo lo 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.
Construyo un pequeño script bash (en github) basado en la sugerencia de David usando el comando file
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 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.
El compilador de Java ( javac
) no construye archivos jar, traduce archivos Java en archivos de clase. La herramienta Jar ( jar
) crea los tarros reales. Si no se especificó ningún manifiesto personalizado, el manifiesto predeterminado especificará qué versión del JDK se utilizó para crear el jar.
En Windows, haga lo siguiente:
- Descomprime o extrae el archivo JAR usando el comando WinZip / Java JAR.
- Arrastre y suelte uno de los archivos de clase en su proyecto Eclipse Java.
- Abra el archivo de clase.
Ahora Eclipse mostrará la versión mayor y menor exacta.
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 usarlos una sola vez 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 lo señala , no puedes confiar 100% en el manifiesto para decirte algo útil. Si fuera así, puedes sacarlo en tu 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
Este .jar no tiene nada útil en el manifiesto sobre las clases contenidas.
Muchas veces, es posible que esté mirando archivos jar completos o archivos war que contienen muchos archivos jar además de ellos mismos.
Como no quería verificar manualmente cada clase, escribí un programa de 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 qué JDK podrá CARGAR las clases, que es probablemente con lo que quería comenzar.
No es necesario descomprimir el JAR (si se conoce uno de los nombres de clase o se busca, por ejemplo, utilizando 7zip), por lo que en Windows sería suficiente:
javap -cp log4j-core-2.5.jar -verbose org.apache.logging.log4j.core.Logger | findstr major
No se puede decir desde el archivo JAR, necesariamente.
Descargue un editor hexadecimal y abra uno de los archivos de clase dentro del JAR y observe los desplazamientos de bytes 4 a 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 te dicen para qué versión se ha compilado la clase, no qué versión compiló.
Para ampliar McDowell''s respuestas de Jonathon Faust y McDowell''s : Si tiene un sistema basado en * nix, puede usar od
(uno de los primeros programas de Unix 1 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
Esto dará como resultado 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)
Puede decirle a la versión binaria de Java inspeccionando los primeros 8 bytes (o usando una app que sí puede).
El compilador, a mi entender, no inserta ninguna firma identificativa. No puedo detectar tal cosa en el formato de la clase de especificación de VM de todos modos.
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
Un jar
es simplemente un contenedor. Es un archivo de archivo a la tar
. Si bien un contenedor puede contener información interesante dentro de su jerarquía META-INF , no tiene la obligación de especificar la antigüedad de las clases dentro de sus contenidos. Para eso, uno debe examinar los archivos de class
mismo.
Tal como lo mencionó Peter Lawrey en el comentario de la pregunta original, no necesariamente puede saber qué versión de JDK compiló un archivo de class
determinado, pero puede averiguar la versión de la class
código de bytes del archivo de class
contenido en un contenedor.
Sí, esto apesta, 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 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 acertadamente señala:
$ javap -v ./org/apache/log4j/Appender.class | grep major
major version: 45
Y si está relegado a un entorno de Windows
sin file
o grep
> javap -v ./org/apache/log4j/Appender.class | findstr major
major version: 45
FWIW, coincidiré en que javap
contará mucho más sobre un archivo de class
determinado 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
El número principal de la versión de clase 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
Un trazador de líneas (Linux)
unzip -p mylib.jar META-INF/MANIFEST.MF
Esto imprime el contenido del archivo MANIFEST.MF
en stdout (esperemos que haya uno en su archivo jar :)
Dependiendo de qué construyó su paquete, encontrará la versión JDK en la clave Created-By
o Build-Jdk
.
Usted marca el archivo Manifiesto del ejemplo jar:
Manifest-Version: 1.0 Created-By: 1.6.0 (IBM Corporation)