37 votes

API Java pour connaître la version du JDK pour laquelle un fichier de classe a été compilé ?

Existe-t-il des API Java permettant de connaître la version du JDK pour laquelle un fichier de classe a été compilé ? Bien sûr, il y a l'outil javap qui permet de connaître la version majeure, comme indiqué dans le document suivant. ici . Cependant, je veux le faire de manière programmatique afin de pouvoir avertir l'utilisateur de le compiler pour le JDK approprié.

1 votes

Les réponses qui impliquent la lecture d'octets à partir d'un fichier me semblent assez peu civilisées. Il devrait y avoir un moyen d'obtenir ces informations à l'aide de Reflection, comme Foobar.class.getTargetVersion().

52voto

RealHowTo Points 13117
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();
    }
}

Les valeurs possibles sont :

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
54       0           10
55       0           11
56       0           12
57       0           13
58       0           14

18voto

rickumali Points 425

L'approche de basszero peut être réalisée via la ligne de commande UNIX, et la commande "od(1)" :

% 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" est le nombre magique . Le "0000 3100" est 0x31, ce qui représente J2SE 5.0.

8voto

Michael Borgwardt Points 181658

Vous obtenez ainsi le contenu du fichier de classe :

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

Il faut ensuite examiner les octets 5 à 8 pour obtenir la version mineure et majeure. Une correspondance entre ces numéros et les versions du JDK peut être trouvée. ici .

0 votes

L'argument chaîne doit-il être entièrement qualifié ? getResourceAsStream("org/apache/foobar/Whatever.class") ?

0 votes

Non, puisque vous utilisez la classe elle-même comme base pour obtenir la ressource. Vous avez besoin du nom pleinement qualifié si vous pouvez utiliser les méthodes getResource du ClassLoader au lieu d'une classe.

7voto

skaffman Points 197885

Apache BCEL fournit cette API :

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

5voto

basszero Points 14539

Il suffit de lire le fichier de classe directement. Il est TRES facile de déterminer la version. Vérifiez le spec et wiki et ensuite essayer le code. Envelopper ce code et le rendre plus utile/joli est laissé comme un exercice. Vous pouvez également utiliser une bibliothèque comme BCEL , ASM ou 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();
        }
    }

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X