Java: Allgemeinere Methodensignatur gibt mir einen NoSuchMethodError

8

Es gibt ein Jar, das, wenn es erstellt wurde, eine Methode MyClass.doSomething(List) verwenden sollte. Diese Methode wurde in doSomething(Collection) geändert und in ein anderes jar (nur mit dieser Klasse) eingefügt.

Ich lege mein zweites Glas vor mein erstes Glas im Klassenpfad, aber wenn der Code in meinem ersten Glas MyClass.doSomething() mit einer Liste aufruft, bekomme ich immer noch ein

  

java.lang.NoSuchMethodError: MyClass.doSomething(Ljava/util/List;)Ljava/util/List;

Wie ist das möglich? Ant wurde verwendet, um die Gläser zu kompilieren.

    
Jordan 12.05.2011, 11:28
quelle

2 Antworten

11

Es gibt einen wichtigen Unterschied zwischen Quellkompatibilität und Binärkompatibilität.

  • Wenn zwei Versionen einer Klasse V1 und V2 binärkompatibel sind, bedeutet das, dass gegen V1 kompilierte Klassen gegen V2 gut laufen.
  • Wenn zwei Versionen einer Klasse V1 und V2 Quellkompatibel sind, bedeutet dies, dass eine Klasse, die gegen V1 kompilieren könnte, gegen V2 gut kompiliert wird.

Bei der Quellkompatibilität bedeutet nicht automatisch die Binärkompatibilität, wie Sie bereits festgestellt haben.

Wenn die Quelle kompiliert wird, wird die spezifische Methodensignatur, die aufgerufen werden soll, vom Compiler entschieden und in der Datei .class gespeichert (in diesem Fall ist es doSomething(List) ).

Wenn die Klasse geändert wird und die Methode doSomething(List) entfernt wird, während doSomething(Collection) hinzugefügt wird, wird die Quellkompatibilität beibehalten (weil Sie einfach denselben Code für die neue Klasse kompilieren können), aber die Binärkompatibilität ist verloren!

Die Java-Sprachspezifikation enthält einen vollständigen Abschnitt zur Binärkompatibilität .

Zusammenfassend: Während das Ändern des Argumenttyps einer Methode auf einen allgemeineren Typ (normalerweise) quellkompatibel ist, ist es nicht binärkompatibel.

Wenn Sie die Binärkompatibilität beibehalten möchten, müsste die Änderung wie folgt aussehen:

%Vor%     
Joachim Sauer 12.05.2011 11:38
quelle
4

Wenn Sie NoSuchMethodError erhalten, heißt das im Allgemeinen, dass die zur Laufzeit verwendete Version der Zielklasse sich von der Version der Zielklasse unterscheidet, für die die aufrufende Klasse kompiliert wurde. In Ihrem Fall ist es kein überraschender Fehler; Der Bytecode in der ersten JAR wird weiterhin gegen das Vorhandensein einer Methode kompiliert, die ein List , das nicht existiert , verwendet.

Dies könnte auf die inkrementelle Kompilierung von Ant zurückzuführen sein, die nicht bemerkt, dass sich abhängige Klassen geändert haben, oder etwas ähnliches.

Wenn Sie eine saubere Wiederherstellung des gesamten Projekts durchführen (zumindest die von Ihnen erwähnten JARs), sollte dieses Problem gelöst werden, da der Compiler Bytecode erstellt, der die neue doSomething Signatur aufruft.

    
Andrzej Doyle 12.05.2011 11:37
quelle