2009-08-18 12 views
34

Esistono API Java per scoprire la versione JDK per cui è stato compilato un file di classe? Naturalmente c'è lo strumento javap per scoprire la versione principale come menzionato in here. Tuttavia, desidero farlo a livello di codice in modo che possa avvisare l'utente di compilarlo per l'appropriato JDKAPI Java per scoprire la versione JDK per cui è stato compilato un file di classe?

+1

Le risposte che implicano la lettura di byte da un file mi sembrano abbastanza incivili. Ci dovrebbe essere un modo per ottenere queste informazioni usando Reflection, come ad esempio Foobar.class.getTargetVersion(). –

risposta

45
import java.io.*; 
public class ClassVersionChecker { 
public static void main(String[] args) throws IOException { 
    for (int i = 0; i < args.length; i++) 
     checkClassVersion(args[i]); 
} 

    private static void checkClassVersion(String filename) 
     throws IOException 
    { 
     DataInputStream in = new DataInputStream 
     (new FileInputStream(filename)); 

     int magic = in.readInt(); 
     if(magic != 0xcafebabe) { 
      System.out.println(filename + " is not a valid class!");; 
     } 
     int minor = in.readUnsignedShort(); 
     int major = in.readUnsignedShort(); 
     System.out.println(filename + ": " + major + " . " + minor); 
     in.close(); 
    } 
} 

I valori possibili sono:

major minor Java platform version 
45  3   1.0 
45  3   1.1 
46  0   1.2 
47  0   1.3 
48  0   1.4 
49  0   5 
50  0   6 
51  0   7 
52  0   8 
53  0   9 
0

JavaP ha uno API, ma è specifico per Sun JDK.

Si trova in tools.jar, sotto sun/tools/javap/Main.class.

8

Questo si il contenuto del file di classe ottiene:

MysteryClass.class.getResourceAsStream("MysteryClass.class")

Poi guardate byte 5-8 per ottenere il minore e versione principale. Una mappatura tra quei numeri e le versioni JDK può essere trovata here.

+0

L'argomento stringa dovrebbe essere pienamente qualificato? getResourceAsStream ("org/apache/foobar/Whatever.class")? –

+0

No, dal momento che si sta utilizzando la classe stessa come base per ottenere la risorsa. È necessario il nome completo se è possibile ottenere metodi Resource di ClassLoader anziché di una classe. –

5

Basta leggere direttamente il file di classe. È MOLTO facile da capire la versione. Controlla il spec e wiki e poi prova il codice. Avvolgere questo codice e renderlo più utile/bello è lasciato come esercizio. In alternativa, è possibile utilizzare una libreria come BCEL, ASM, o JavaAssist

import java.io.DataInputStream; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 

public class ClassVersionTest 
{ 
    private static final int JAVA_CLASS_MAGIC = 0xCAFEBABE; 

    public static void main(String[] args) 
    { 
     try 
     { 
      DataInputStream dis = new DataInputStream(new FileInputStream("Test.class")); 
      int magic = dis.readInt(); 
      if(magic == JAVA_CLASS_MAGIC) 
      { 
       int minorVersion = dis.readUnsignedShort(); 
       int majorVersion = dis.readUnsignedShort(); 

       /** 
       * majorVersion is ... 
       * J2SE 6.0 = 50 (0x32 hex), 
       * J2SE 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). 
       */ 

       System.out.println("ClassVersionTest.main() " + majorVersion + "." + minorVersion); 
      } 
      else 
      { 
       // not a class file 
      } 
     } 
     catch (FileNotFoundException e) 
     { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     catch (IOException e) 
     { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

} 
+0

Funzionerà per i file di classe in un barattolo? –

2

Come altri hanno già dimostrato, è abbastanza facile da fare leggendo i primi otto byte di un file di classe. Se si desidera una libreria binaria precostruita, è possibile scaricare uno here.

7

Apache BCEL fornisce questa API:

JavaClass c = Repository.lookupClass("com.x.MyClass") 
c.getMinor(); 
c.getMajor(); 
17

approccio di basszero può essere effettuata tramite la linea di comando UNIX, e il "od (1)" comando:

% od -x HelloWorldJava.class |head -2 
0000000 feca beba 0000 3100 dc00 0007 0102 2a00 
0000020 6f63 2f6d 6e65 6564 6163 642f 6d65 2f6f 

"feca beba" è il magic number. "0000 3100" è 0x31, che rappresenta J2SE 5.0.

2

Su Linux, è possibile utilizzare il comando file su un file di classe, che ho trovato più semplice per il mio caso d'uso. Ad esempio:

$ file Foo.class 
Foo.class: compiled Java class data, version 50.0 (Java 1.6) 
Problemi correlati