| Ceci est un problème que je rencontre souvent dans mes développements JAVA/J2EE étant donnée que j'utilise 3 versions de JDK (1.4 pour le boulot, 1.5 comme JVM par défaut, et 1.6 selon certaines besoins). Rien de bien méchant, il me suffit de changer le JAVA_HOME pour pointer vers la bonne version :). Tout le souci est de savoir qu'elle est cette bonne version. En mode lazy, on switchera vers la version la plus récente, mais cela peut avoir des conséquences assez gênantes/fatals, si votre environnement de déploiement tourne sur ancienne version pour une raison ou autres (politique, développement embarqué/pour mobile, ...). L'Erreur java.lang.UnsupportedClassVersionErrorL'erreur se produit sous la forme : Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad version number in .class fileat java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClass(Unknown Source)
 at java.security.SecureClassLoader.defineClass(Unknown Source)
 at java.net.URLClassLoader.defineClass(Unknown Source)
 at java.net.URLClassLoader.access$100(Unknown Source)
 at java.net.URLClassLoader$1.run(Unknown Source)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(Unknown Source)
 at java.lang.ClassLoader.loadClass(Unknown Source)
 at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
 at java.lang.ClassLoader.loadClass(Unknown Source)
 at java.lang.ClassLoader.loadClassInternal(Unknown Source)
 ou encore: 
 java.lang.UnsupportedClassVersionError:  Main (Unsupported major.minor version 49.0)
 ou encore  class version mismatch. Les versions des  fichiers classes JavaLa version Java est contenue dans chaque fichier class, ce tableau référence les différentes versions, et la correspondance  entre le code version "interne" et le code version "humain".  
    
        
            | major version | Version Java | Valeur hexa |  |  
            | 45 | 1.0 ou 1.1 | 2D | Chapeau d'avoir trouvé une class aussi vielle :D |  
            | 46 | 1.2 | 2E |  |  
            | 47 | 1.3 | 2F |  |  
            | 48 | 1.4 | 30 | Assert |  
            | 49 | 5.0 | 31 | @rocks :) |  
            | 50 | 6 | 32 | Powa |  
            | 51 | 7 | 33 | invokedynamic |  
            | 52 | 8 | 34 | lambda |  
            | 53 | 9 | 35 | jigsaw |  Trouver la bonne version d'un fichier .classAu lieu de jouer au pif afin de savoir quel version de la JVM il faut utiliser, et éviter les risques cité ci-haut, il faut trouver la bonne version à utiliser. Les moyens sont multiples : Linux Wayle fameux outil "file". $ file Main.class Main.class: compiled Java class data, version 49.0
 vous pouvez même l'enrichir en modifiant le fichier magic number (sous ubuntu : /etc/magic) : 0 belong 0xcafebabe      Fichier Class JavaCe qui donne un truc plus cool/frenchy :>6      beshort          x               Version Majeur %d.
 >6      beshort          =45             Necessite JRE 1.1 ou supérieur
 >6      beshort          =46             Necessite JRE 1.2 ou supérieur
 >6      beshort          =47             Necessite JRE 1.3 ou supérieur
 >6      beshort          =48             Necessite JRE 1.4 ou supérieur
 >6      beshort          =49             Necessite JRE 5.0 ou supérieur
 >6      beshort          =50             Necessite JRE 6.0 ou supérieur
 >6      beshort          >50             Necessite JRE 7 ou supérieur
 $ file Main.classMain.class: Fichier Class Java Version Majeur 49. Necessite JRE 5.0 ou supérieur
 
 avec JDK 1.4si vous possédez une JDK 1.4, le numéro de version est affiché dans le message d'erreur, comme vu plus haut (49.0). javap (Java Disamsembler) /JDK 1.5si vous possédez la JDK 1.5 ou supérieur, le plus simple est de lancer javap (Java Disamsembler ) sur le class qui cause le soucis : $ javap -verbose Main | head -n 10
 Compiled from "Main.java"class Main extends java.lang.Object
 SourceFile: "Main.java"
 minor version: 0
 
major version: 49Constant pool:
 const #1 = Method    #6.#15;    //  java/lang/Object."<init>":()V
 const #2 = Field    #16.#17;    //  java/lang/System.out:Ljava/io/PrintStream;
 const #3 = String    #18;    //  Hello world
 const #4 = Method    #19.#20;    //  java/io/PrintStream.println:(Ljava/lang/String;)V
 
 Le code qui nous intéresse se trouve au tout début, le reste c'est le byte-code java désassemblé. Geek way
La méthode la plus ..."geek" est de faire appel à hexdump ou à votre éditeur hexadécimal préféré, pour cela il faudra connaitre le format du fichier .Class qui est le suivant : 4 premiers octets : correspondent à la 0xCAFEBABE : c'est le magic number qui définit que le fichier est un fichier .class, ensuite viennent 4 octets représentant les versions, ils sont séparés en deux séries (de deux octets) : la version mineur (je me demande si ca sert à quel chose), et la fameuse version majeur qui nous intéresse :) pour plus d'informations sur le format des fichiers .class vous pouvez consulter la doc SUNdoc Oracle, ou la page wikipedia. Générer un fichier Class pour une version JDK donnéeEt pour finir sachez que, si besoin, vous pouvez générer une class pour une version donnée, grâce aux paramètres -source et -target de javac :
 $ javac -versionjavac 1.6.0_07
 $ javac -target 1.4  Main.java
 -bootclasspath /opt/java.old/j2re1.4.2_18/lib/rt.jar $ file Main.class
 Main.class: Fichier Class Java Version Majeur 48. Necessite JRE 1.4 ou supérieur
   Le compilateur java, en vérifiant le code va chercher les classes "internes" dans le chemin relative à javac. L'option -bootclasspath permet de changer ca, de cette façon on fait ce qu'on appelle du cross-compiling, et on évite certaines erreurs qui ne se détectent qu'au moment de l'exécution du style  java.lang.NoSuchMethodError. Pour plus d'informations sur ce genre de problème, vous pouvez consulter l'article suivant. Pour récupérer une vieille version du JRE/JDK, consultez le site de sun ou les archives. Si vous utilisez jdk 1.5 ou supérieur, vous pouvez aussi rencontrez des soucis pour compiler pour une vielle version : javac: target release 1.4 conflicts with default source release 1.5. il s'agit en fait des assertions introduites dans la version 1.4 de java. Il faudra donc spécifier au compilateur quel version choisir (1.3 désactive, 1.4, 1.5 ...).   Sur ce, je vous souhaite un bon café :)     |