J'empaquette une bibliothèque Java en tant que JAR, et cela lance de nombreux java.lang.IncompatibleClassChangeError
s lorsque j'essaie d'en appeler des méthodes. Ces erreurs semblent apparaître au hasard. Quels types de problèmes peuvent être à l'origine de cette erreur?
java
jar
runtime-error
binary-compatibility
Des morts-vivants
la source
la source
Réponses:
Cela signifie que vous avez apporté des modifications binaires incompatibles à la bibliothèque sans recompiler le code client. La spécification du langage Java §13 détaille toutes ces modifications, surtout, en changeant
static
les champs / méthodes non-privés pour êtrestatic
ou vice versa.Recompilez le code client contre la nouvelle bibliothèque, et vous devriez être prêt à partir.
MISE À JOUR: Si vous publiez une bibliothèque publique, vous devez éviter autant que possible d'apporter des modifications binaires incompatibles afin de préserver ce que l'on appelle la «compatibilité descendante binaire». La mise à jour des pots de dépendance ne devrait idéalement pas, à elle seule, interrompre l'application ou la build. Si vous devez rompre la compatibilité descendante binaire, il est recommandé d'augmenter le numéro de version principal (par exemple de 1.xy à 2.0.0) avant de publier la modification.
la source
*.class
fichiers) et une recompilation? L'édition de fichiers a un effet similaire.Votre bibliothèque nouvellement empaquetée n'est pas binaire rétrocompatible (BC) avec l'ancienne version. Pour cette raison, certains des clients de bibliothèque qui ne sont pas recompilés peuvent lever l'exception.
Il s'agit d'une liste complète des modifications de l'API de la bibliothèque Java qui peuvent amener les clients créés avec une ancienne version de la bibliothèque à lancer java.lang. IncompatibleClassChangeError s'ils s'exécutent sur un nouveau (c'est-à-dire en cassant BC):
Remarque : Il existe de nombreuses autres exceptions causées par d'autres modifications incompatibles: NoSuchFieldError , NoSuchMethodError , IllegalAccessError , InstantiationError , VerifyError , NoClassDefFoundError et AbstractMethodError .
Le meilleur article sur BC est "Evolving Java-based APIs 2: Achieving API Binary Compatibility" écrit par Jim des Rivières.
Il existe également des outils automatiques pour détecter de tels changements:
Utilisation de japi-compliance-checker pour votre bibliothèque:
Utilisation de l'outil clirr:
Bonne chance!
la source
Bien que ces réponses soient toutes correctes, la résolution du problème est souvent plus difficile. Il est généralement le résultat de deux versions légèrement différentes de la même dépendance à l'classpath, et est presque toujours causée soit par un autre superclasse que ce qui était à l' origine compilé contre être sur le chemin de classe ou une importation de la fermeture transitive étant différente, mais généralement à la classe instanciation et invocation de constructeur. (Après un chargement de classe et une invocation de ctor réussis, vous obtiendrez
NoSuchMethodException
ou autre chose.)Si le comportement semble aléatoire, c'est probablement le résultat d'un programme multithread chargeant différentes dépendances transitives en fonction du code obtenu en premier.
Pour résoudre ces problèmes, essayez de lancer la machine virtuelle avec
-verbose
comme argument, puis examinez les classes en cours de chargement lorsque l'exception se produit. Vous devriez voir des informations surprenantes. Par exemple, avoir plusieurs copies de la même dépendance et des versions auxquelles vous ne vous attendiez pas ou que vous auriez acceptées si vous saviez qu'elles étaient incluses.La résolution des pots en double avec Maven est mieux fait avec une combinaison de maven-dépendance-plugin et plugin Maven-enforcer- sous Maven (ou de SBT dépendance graphique Plugin , puis en ajoutant les pots à une section de votre haut niveau POM ou la dépendance importés éléments dans SBT (pour supprimer ces dépendances).
Bonne chance!
la source
J'ai également découvert que, lorsque vous utilisez JNI, en invoquant une méthode Java à partir de C ++, si vous passez des paramètres à la méthode Java invoquée dans le mauvais ordre, vous obtiendrez cette erreur lorsque vous tenterez d'utiliser les paramètres à l'intérieur de la méthode appelée (car ils ne sera pas le bon type). J'ai d'abord été surpris que JNI n'effectue pas cette vérification pour vous dans le cadre de la vérification de signature de classe lorsque vous appelez la méthode, mais je suppose qu'ils ne font pas ce type de vérification car vous pouvez passer des paramètres polymorphes et ils doivent supposez que vous savez ce que vous faites.
Exemple de code C ++ JNI:
Exemple de code Java:
la source
J'ai eu le même problème, et plus tard j'ai compris que j'exécutais l'application sur Java version 1.4 tandis que l'application est compilée sur la version 6.En fait, la raison était d'avoir une bibliothèque en double, l'une est située dans le chemin de classe et l'autre est incluse dans un fichier jar qui se trouve dans le chemin de classe.
la source
Une autre situation où cette erreur peut apparaître est avec la couverture de code Emma.
Cela se produit lors de l'affectation d'un objet à une interface. Je suppose que cela a quelque chose à voir avec l'objet étant instrumenté et non plus compatible binaire.
http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351
Heureusement, ce problème ne se produit pas avec Cobertura, j'ai donc ajouté cobertura-maven-plugin dans mes plugins de reporting de mon pom.xml
la source
J'ai rencontré ce problème lors du retrait et du redéploiement d'une guerre avec le poisson-verre. Ma structure de classe était comme ça,
et il a été changé en
Après avoir arrêté et redémarré le domaine, cela a bien fonctionné. J'utilisais Glassfish 3.1.43
la source
J'ai une application Web qui se déploie parfaitement sur le tomcat de ma machine locale (8.0.20). Cependant, quand je l'ai mis dans l'environnement qa (tomcat - 8.0.20), il a continué à me donner l'IncompatibleClassChangeError et il se plaignait que je m'étendais sur une interface. Cette interface a été remplacée par une classe abstraite. Et j'ai compilé les classes parents et enfants et j'ai continué à obtenir le même problème. Enfin, je voulais déboguer, j'ai donc changé la version du parent en x.0.1-SNAPSHOT, puis j'ai tout compilé et maintenant ça fonctionne. Si quelqu'un rencontre toujours le problème après avoir suivi les réponses données ici, assurez-vous que les versions de votre pom.xml sont également correctes. Modifiez les versions pour voir si cela fonctionne. Si c'est le cas, corrigez le problème de version.
la source
Je crois que ma réponse sera spécifique à Intellij.
J'avais reconstruit propre, allant même jusqu'à supprimer manuellement les répertoires "out" et "target". Intellij a un "invalider les caches et redémarrer", ce qui efface parfois les erreurs impaires. Cette fois, cela n'a pas fonctionné. Les versions des dépendances semblaient toutes correctes dans le menu des paramètres du projet-> modules.
La réponse finale a été de supprimer manuellement ma dépendance au problème de mon référentiel Maven local. Une ancienne version de bouncycastle était le coupable (je savais que je venais de changer de version et ce serait le problème) et même si l'ancienne version ne montrait aucun endroit dans ce qui était en cours de construction, elle a résolu mon problème. J'utilisais l'intellij version 14, puis mis à niveau vers 15 au cours de ce processus.
la source
Dans mon cas, j'ai rencontré cette erreur de cette façon.
pom.xml
de mon projet a défini deux dépendancesA
etB
. Et les deuxA
et laB
dépendance définie sur le même artefact (appelez-leC
) mais des versions différentes de celui-ci (C.1
etC.2
). Lorsque cela se produit, pour chaque classe deC
maven, vous ne pouvez sélectionner qu'une seule version de la classe parmi les deux versions (lors de la construction d'un uber-jar ). Il sélectionnera la version "la plus proche" en fonction de ses règles de médiation de dépendance et affichera un avertissement "Nous avons une classe en double ..." Si une signature de méthode / classe change entre les versions, cela peut provoquer unejava.lang.IncompatibleClassChangeError
exception si la version incorrecte est utilisé lors de l'exécution.Avancé: si vous
A
devez utiliser la v1 deC
etB
devez utiliser la v2 deC
, nous devons déplacer les pomsC
dansA
etB
pour éviter les conflits de classe (nous avons un avertissement de classe en double) lors de la construction du projet final qui dépend à la fois deA
etB
.la source
Dans mon cas, l'erreur est apparue lorsque j'ai ajouté la
com.nimbusds
bibliothèque dans mon application déployée surWebsphere 8.5
.L'exception ci-dessous s'est produite:
La solution était d'exclure le pot asm de la bibliothèque:
la source
Veuillez vérifier si votre code ne se compose pas de deux projets de module qui ont les mêmes noms de classes et définitions de packages. Par exemple, cela peut se produire si quelqu'un utilise le copier-coller pour créer une nouvelle implémentation d'interface basée sur une implémentation précédente.
la source
S'il s'agit d'un enregistrement des occurrences possibles de cette erreur, alors:
Je viens de recevoir cette erreur sur WAS (8.5.0.1), lors du chargement CXF (2.6.0) de la configuration de printemps (3.1.1_release) où une BeanInstantiationException a généré une CXF ExtensionException, en remontant une IncompatibleClassChangeError. L'extrait suivant montre l'essentiel de la trace de la pile:
Dans ce cas, la solution a été de changer l'ordre des chemins de classe du module dans mon fichier war. Autrement dit, ouvrez l'application War dans la console WAS sous et sélectionnez le ou les modules client. Dans la configuration du module, définissez le chargement de classe sur "dernier parent".
Cela se trouve dans la console WAS:
la source
Documenter un autre scénario après avoir brûlé trop de temps.
Assurez-vous que vous n'avez pas de fichier de dépendance contenant une classe avec une annotation EJB.
Nous avions un fichier jar commun qui avait une
@local
annotation. Cette classe a ensuite été déplacée hors de ce projet commun et dans notre projet de pot ejb principal. Notre pot ejb et notre pot commun sont tous deux regroupés dans une oreille. La version de notre dépendance jar commune n'a pas été mise à jour. Ainsi 2 classes essaient d'être quelque chose avec des changements incompatibles.la source
Tout ce qui précède - pour une raison quelconque, je faisais un gros remaniement et commençais à l'obtenir. J'ai renommé le package dans lequel mon interface était et cela l'a effacé. J'espère que cela pourra aider.
la source
Pour une raison quelconque, la même exception est également levée lors de l'utilisation de JNI et de la transmission de l'argument jclass au lieu du jobject lors de l'appel de a
Call*Method()
.Ceci est similaire à la réponse du Psaume Ogre33.
Je sais qu'il est un peu tard pour répondre à cette question 5 ans après avoir été posé, mais c'est l'un des meilleurs succès lors de la recherche,
java.lang.IncompatibleClassChangeError
donc je voulais documenter ce cas particulier.la source
Ajouter mes 2 cents. Si vous utilisez scala et sbt et scala-logging comme dépendance; alors cela peut arriver parce que la version précédente de scala-logging avait le nom scala-logging-api.So; essentiellement, les résolutions de dépendance ne se produisent pas en raison de différences noms menant à des erreurs d'exécution lors du lancement de l'application scala.
la source
Une autre cause de ce problème est si vous avez
Instant Run
activé Android Studio.Le correctif
Si vous constatez que vous commencez à obtenir cette erreur, désactivez-la
Instant Run
.Pourquoi
Instant Run
modifie un grand nombre de choses pendant le développement, pour accélérer la mise à jour de votre application en cours d'exécution. D'où une course instantanée. Quand ça marche, c'est vraiment utile. Cependant, lorsqu'un problème comme celui-ci se produit, la meilleure chose à faire est de désactiverInstant Run
jusqu'à la sortie de la prochaine version d'Android Studio.la source