Ich packe eine Java-Bibliothek als JAR und es werden viele java.lang.IncompatibleClassChangeError
s ausgelöst, wenn ich versuche, Methoden daraus aufzurufen. Diese Fehler scheinen zufällig zu erscheinen. Welche Probleme könnten diesen Fehler verursachen?
java
jar
runtime-error
binary-compatibility
Zombies
quelle
quelle
Antworten:
Dies bedeutet, dass Sie einige inkompatible binäre Änderungen an der Bibliothek vorgenommen haben, ohne den Clientcode neu zu kompilieren. Java-Sprachspezifikation §13 beschreibt alle derartigen Änderungen, vor allem, indem
static
nicht-nicht-private Felder / Methoden geändert werdenstatic
oder umgekehrt.Kompilieren Sie den Client-Code erneut mit der neuen Bibliothek, und Sie sollten bereit sein.
UPDATE: Wenn Sie eine öffentliche Bibliothek veröffentlichen, sollten Sie inkompatible binäre Änderungen so weit wie möglich vermeiden, um die sogenannte "binäre Abwärtskompatibilität" beizubehalten. Das Aktualisieren von Abhängigkeitsgläsern allein sollte im Idealfall weder die Anwendung noch den Build beschädigen. Wenn Sie die binäre Abwärtskompatibilität unterbrechen müssen, wird empfohlen , die Hauptversionsnummer (z. B. von 1.xy auf 2.0.0) zu erhöhen, bevor Sie die Änderung freigeben.
quelle
*.class
Dateien löschen ) und neu zu kompilieren? Das Bearbeiten von Dateien hat einen ähnlichen Effekt.Ihre neu gepackte Bibliothek ist nicht abwärtsbinärkompatibel (BC) mit der alten Version. Aus diesem Grund können einige der nicht neu kompilierten Bibliotheksclients die Ausnahme auslösen.
Dies ist eine vollständige Liste der Änderungen in der Java-Bibliotheks-API, die dazu führen können, dass Clients, die mit einer alten Version der Bibliothek erstellt wurden, java.lang auslösen. IncompatibleClassChangeError, wenn sie auf einem neuen ausgeführt werden (dh BC brechen):
Hinweis : Es gibt viele andere Ausnahmen, die durch andere inkompatible Änderungen verursacht werden: NoSuchFieldError , NoSuchMethodError , IllegalAccessError , InstantiationError , VerifyError , NoClassDefFoundError und AbstractMethodError .
Das bessere Papier über BC ist "Evolving Java-based APIs 2: Erreichen der binären API-Kompatibilität", geschrieben von Jim des Rivières.
Es gibt auch einige automatische Tools , um solche Änderungen zu erkennen:
Verwendung des Japi-Compliance-Checkers für Ihre Bibliothek:
Verwendung des Clirr-Werkzeugs:
Viel Glück!
quelle
Obwohl diese Antworten alle richtig sind, ist die Lösung des Problems oft schwieriger. Dies ist im Allgemeinen das Ergebnis von zwei leicht unterschiedlichen Versionen derselben Abhängigkeit vom Klassenpfad und wird fast immer entweder durch eine andere Oberklasse als ursprünglich kompiliert, die ursprünglich gegen das Befinden im Klassenpfad kompiliert wurde, oder durch einen unterschiedlichen Import des transitiven Abschlusses, jedoch im Allgemeinen in der Klasse Instanziierung und Konstruktoraufruf. (Nach erfolgreichem Laden der Klasse und ctor-Aufruf erhalten Sie
NoSuchMethodException
oder so weiter.)Wenn das Verhalten zufällig erscheint, ist es wahrscheinlich das Ergebnis eines Multithread-Programms, das verschiedene transitive Abhängigkeiten lädt, je nachdem, welcher Code zuerst getroffen wurde.
Um diese Probleme zu beheben, starten Sie die VM mit
-verbose
einem Argument und sehen Sie sich dann die Klassen an, die geladen wurden, als die Ausnahme auftrat. Sie sollten einige überraschende Informationen sehen. Wenn Sie beispielsweise mehrere Kopien derselben Abhängigkeit und Versionen haben, die Sie nie erwartet hätten oder die Sie akzeptiert hätten, wenn Sie gewusst hätten, dass sie enthalten sind.Beheben doppelte Gläser mit Maven wird am besten mit einer Kombination aus der getan Maven-Abhängigkeit-Plugin und maven-Enforcer-Plugin unter Maven (oder die SBT Dependency Graph Plugin , dann die Gläser auf einen Abschnitt Ihres Top-Level POM oder als importierte Abhängigkeit Zugabe Elemente in SBT (um diese Abhängigkeiten zu entfernen).
Viel Glück!
quelle
Ich habe auch festgestellt, dass bei Verwendung von JNI beim Aufrufen einer Java-Methode aus C ++, wenn Sie Parameter in der falschen Reihenfolge an die aufgerufene Java-Methode übergeben, dieser Fehler angezeigt wird, wenn Sie versuchen, die Parameter in der aufgerufenen Methode zu verwenden (weil sie wird nicht der richtige Typ sein). Ich war anfangs überrascht, dass JNI diese Prüfung nicht als Teil der Klassensignaturprüfung für Sie durchführt, wenn Sie die Methode aufrufen, aber ich gehe davon aus, dass sie diese Art der Prüfung nicht durchführen, weil Sie möglicherweise polymorphe Parameter übergeben und dies müssen Angenommen, Sie wissen, was Sie tun.
Beispiel C ++ JNI Code:
Beispiel Java Code:
quelle
Ich hatte das gleiche Problem und später stellte ich fest, dass ich die Anwendung auf Java Version 1.4 ausführe, während die Anwendung auf Version 6 kompiliert wird.Der Grund war, dass eine doppelte Bibliothek vorhanden war, eine im Klassenpfad und die andere in einer JAR-Datei, die sich im Klassenpfad befindet.
quelle
Eine andere Situation, in der dieser Fehler auftreten kann, ist Emma Code Coverage.
Dies geschieht, wenn einer Schnittstelle ein Objekt zugewiesen wird. Ich denke, das hat etwas damit zu tun, dass das Objekt instrumentiert und nicht mehr binär kompatibel ist.
http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351
Glücklicherweise tritt dieses Problem bei Cobertura nicht auf, daher habe ich das Cobertura-Maven-Plugin in meinen Berichts-Plugins meiner pom.xml hinzugefügt
quelle
Ich habe mich diesem Problem gestellt, als ich einen Krieg mit Glasfischen aufgehoben und wieder eingesetzt habe. Meine Klassenstruktur war so,
und es wurde geändert zu
Nach dem Stoppen und Neustarten der Domain hat es gut funktioniert. Ich habe Glassfish 3.1.43 verwendet
quelle
Ich habe eine Webanwendung, die problemlos auf dem Tomcat meines lokalen Computers (8.0.20) bereitgestellt werden kann. Als ich es jedoch in die QA-Umgebung (Tomcat - 8.0.20) einfügte, gab es mir weiterhin den IncompatibleClassChangeError und es beschwerte sich, dass ich eine Schnittstelle erweiterte. Diese Schnittstelle wurde in eine abstrakte Klasse geändert. Und ich habe die Eltern- und Kinderklassen zusammengestellt und trotzdem immer wieder das gleiche Thema bekommen. Schließlich wollte ich debuggen, also habe ich die Version auf dem übergeordneten Element in x.0.1-SNAPSHOT geändert und dann alles kompiliert und jetzt funktioniert es. Wenn das Problem nach den hier angegebenen Antworten immer noch auftritt, stellen Sie bitte sicher, dass auch die Versionen in Ihrer pom.xml korrekt sind. Ändern Sie die Versionen, um festzustellen, ob dies funktioniert. Wenn ja, beheben Sie das Versionsproblem.
quelle
Ich glaube, meine Antwort wird Intellij-spezifisch sein.
Ich hatte sauber neu aufgebaut und ging sogar so weit, die Verzeichnisse "out" und "target" manuell zu löschen. Intellij hat einen "Cache ungültig machen und neu starten", der manchmal ungerade Fehler löscht. Diesmal hat es nicht funktioniert. Die Abhängigkeitsversionen sahen im Menü Projekteinstellungen-> Module alle korrekt aus.
Die endgültige Antwort war, meine Problemabhängigkeit manuell aus meinem lokalen Maven-Repo zu löschen. Eine alte Version von Bouncycastle war der Schuldige (ich wusste, dass ich gerade die Versionen geändert hatte und das wäre das Problem) und obwohl die alte Version nirgends in dem, was gebaut wurde, auftauchte, löste sie mein Problem. Ich habe Intellij Version 14 verwendet und dann während dieses Vorgangs auf 15 aktualisiert.
quelle
In meinem Fall bin ich auf diese Weise auf diesen Fehler gestoßen.
pom.xml
von meinem Projekt definiert zwei AbhängigkeitenA
undB
. Und beideA
undB
definierte Abhängigkeit von demselben Artefakt (nennen wir esC
), aber verschiedenen Versionen davon (C.1
undC.2
). In diesemC
Fall kann für jede Klasse in Maven nur eine Version der Klasse aus den beiden Versionen ausgewählt werden (während ein Uber-Jar erstellt wird ). Es wählt die "nächste" Version basierend auf den Regeln für die Abhängigkeitsvermittlung aus und gibt eine Warnung "Wir haben eine doppelte Klasse ..." aus. Wenn sich eine Methoden- / Klassensignatur zwischen den Versionen ändert, kann dies einejava.lang.IncompatibleClassChangeError
Ausnahme verursachen, wenn die falsche Version vorliegt zur Laufzeit verwendet.Advanced: Wenn
A
muss v1 verwendenC
undB
müssen v2 von verwendenC
, dann müssen wir verlagernC
inA
undB
‚s Poms zu vermeiden Klassenkonflikt (wir haben eine doppelte Klasse Warnung) , wenn das endgültige Projekt Bau, der auf beiden abhängtA
undB
.quelle
In meinem Fall trat der Fehler auf, als ich die
com.nimbusds
Bibliothek in meiner Anwendung hinzugefügt habe, die am bereitgestellt wurdeWebsphere 8.5
.Die folgende Ausnahme ist aufgetreten:
Die Lösung bestand darin, das ASM-Glas aus der Bibliothek auszuschließen:
quelle
Bitte überprüfen Sie, ob Ihr Code nicht aus zwei Modulprojekten besteht, die dieselben Klassennamen und Paketdefinitionen haben. Dies kann beispielsweise passieren, wenn jemand Copy-Paste verwendet, um eine neue Implementierung der Schnittstelle basierend auf der vorherigen Implementierung zu erstellen.
quelle
Wenn dies eine Aufzeichnung möglicher Vorkommen dieses Fehlers ist, dann:
Ich habe gerade diesen Fehler in WAS (8.5.0.1) während des CXF (2.6.0) -Ladens der Spring-Konfiguration (3.1.1_release) erhalten, bei dem eine BeanInstantiationException eine CXF ExtensionException und einen IncompatibleClassChangeError aufgerollt hat. Das folgende Snippet zeigt den Kern der Stapelverfolgung:
In diesem Fall bestand die Lösung darin, die Klassenpfadreihenfolge des Moduls in meiner Kriegsdatei zu ändern. Öffnen Sie also die Kriegsanwendung in der WAS-Konsole unter und wählen Sie die Client-Module aus. Setzen Sie in der Modulkonfiguration das Laden der Klasse auf "last last".
Dies befindet sich in der WAS-Konsole:
quelle
Ein anderes Szenario dokumentieren, nachdem viel zu viel Zeit gebrannt wurde.
Stellen Sie sicher, dass Sie kein Abhängigkeitsglas haben, das eine Klasse mit einer EJB-Annotation enthält.
Wir hatten eine gemeinsame JAR-Datei mit einer
@local
Anmerkung. Diese Klasse wurde später aus diesem gemeinsamen Projekt in unser Hauptprojekt ejb jar verschoben. Unser EJB-Glas und unser gemeinsames Glas sind beide in einem Ohr gebündelt. Die Version unserer allgemeinen JAR-Abhängigkeit wurde nicht aktualisiert. Also 2 Klassen, die versuchen, etwas mit inkompatiblen Änderungen zu sein.quelle
All das oben genannte - aus irgendeinem Grund habe ich einen großen Refactor gemacht und angefangen, das zu bekommen. Ich habe das Paket umbenannt, in dem sich meine Schnittstelle befand, und das hat es gelöscht. Hoffentlich hilft das.
quelle
Aus irgendeinem Grund wird dieselbe Ausnahme auch ausgelöst, wenn JNI verwendet wird und beim Aufrufen von a das Argument jclass anstelle des Jobobjekts übergeben wird
Call*Method()
.Dies ähnelt der Antwort von Ogre Psalm33.
Ich weiß, dass es etwas spät ist, diese Frage 5 Jahre nach der Beantwortung zu beantworten, aber dies ist einer der Top-Hits bei der Suche,
java.lang.IncompatibleClassChangeError
deshalb wollte ich diesen Sonderfall dokumentieren.quelle
Hinzufügen meiner 2 Cent. Wenn Sie scala und sbt und scala-logging als Abhängigkeit verwenden, kann dies passieren, weil die frühere Version von scala-logging den Namen scala-logging-api hatte. Im Wesentlichen passieren die Abhängigkeitsauflösungen nicht aufgrund unterschiedlicher Namen, die beim Starten der Scala-Anwendung zu Laufzeitfehlern führen.
quelle
Eine weitere Ursache für dieses Problem ist, wenn Sie
Instant Run
Android Studio aktiviert haben .Die Reparatur
Wenn Sie feststellen, dass dieser Fehler auftritt, schalten Sie ihn aus
Instant Run
.Warum
Instant Run
Ändert eine große Anzahl von Dingen während der Entwicklung, um die Bereitstellung von Updates für Ihre laufende App zu beschleunigen. Daher sofort laufen. Wenn es funktioniert, ist es wirklich nützlich. Wenn jedoch ein Problem wie dieses auftritt, sollten Sie es am bestenInstant Run
bis zur nächsten Version von Android Studio deaktivieren.quelle