Ich möchte zur Laufzeit eine Implementierung für eine abstrakte Klasse mit Byte Buddy erstellen, und ich stehe vor dem Problem, dass beim Aufruf einer Methode aus einer erstellten Instanz ein java.lang.AbstractMethodError
geworfen wird. Ich habe eine vorhandene abstract
-Klasse wie diese (die ich eigentlich nicht ändern kann und die tatsächlich mehr Logik enthält):
Mit dem folgenden minimalen Beispiel möchte ich, dass meine Algorithm
-Instanz einen konstanten Wert zurückgibt:
Dies führt jedoch zu folgender Ausnahme:
%Vor% (Wenn ich Algorithm
experimentell auf interface
ändere, funktioniert alles einwandfrei, aber das löst mein spezifisches Problem nicht).
Es könnte Sie überraschen, aber genau dasselbe würde passieren, wenn Sie denselben Code mit javac unter Verwendung des gleichen Klassenladeprogramms erstellt hätten. Was Sie beobachten, wird durch die Angabe von package-privacy in der JLS impliziert. Ihre Nicht-Schnittstelle -Klasse
%Vor% definiert eine package-private Methode. Da Sie keinen benutzerdefinierten Namen für die generierte Klasse definieren, generiert Byte Buddy eine Unterklasse mit einem zufälligen Namen, der sich im selben Paket befindet. Byte Buddy entdeckt die Methode executable
als überschreibbar aus der generierten Unterklasse und implementiert sie genau so, wie Sie es erwarten.
Sie verwenden jedoch die Strategie ClassLoadingStrategy.Default.WRAPPER
, um die Klasse zu laden, die ein neues Kindklassenladeprogramm des einen Ladeprogramms Algorithm
erstellt. In Java zur Laufzeit sind zwei Pakete jedoch nur gleich, wenn der Name des Pakets gleich ist und beide Pakete vom selben ClassLoader
geladen werden. Die spätere Bedingung trifft für Ihren Fall nicht zu, sodass die JVM keinen Polymorphismus mehr auf die Klasse execute
anwendet. Durch den Aufruf von
Sie rufen also nicht die erzeugte Methode auf, sondern die ursprüngliche, abstrakte Methode. Daher wird - entsprechend der JLS - ein AbstractMethodError
geworfen.
Um dieses Problem zu beheben, müssen Sie entweder die generierte Klasse im selben Paket mit der Standardstrategie INJECTION
laden oder execute
als public
definieren (dies ist bei der Definition einer Schnittstelle implizit). oder protected
Methode, so dass die Regeln für Polymorphismus, die Sie erwarten, gelten. Als dritte Option können Sie die korrekte Laufzeitmethode mit
Tags und Links java class interface bytecode byte-buddy