Byte Buddy: Erzeuge eine Implementierung für eine abstrakte Klasse

8

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):

%Vor%

Mit dem folgenden minimalen Beispiel möchte ich, dass meine Algorithm -Instanz einen konstanten Wert zurückgibt:

%Vor%

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).

    
qqilihq 10.01.2016, 18:38
quelle

1 Antwort

11

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

%Vor%

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

aufrufen %Vor%     
Rafael Winterhalter 10.01.2016, 22:39
quelle