2016-05-15 4 views
0

Ich versuche, eine Java-Anwendung zu erstellen, die Plugins laden kann, die eine abstrakte Klasse implementieren und einen AbstractMethodError mit den Instanzen haben, die von ServiceLoader generiert werden. Der Code ist ein bisschen schwer, daher habe ich unten eine Vereinfachung vorgenommen.Unterklasse erhalten von Serviceloader wirft AbstractMethodError

Zuerst habe ich eine abstrakte Klasse:

package stuff.TheAbstractClass; 

public abstract class TheAbstractClass implements ClassInterface{ 
//Stuff happens 
} 

, die die unten Schnittstelle implementiert:

package stuff.ClassInterface; 

public interface ClassInterface { 

    public String getClassName(); 

} 

Ich habe einen Dienstleister NotAbstractClass die TheAbstractClass und Staaten so in einer Meta-inf erstreckt/Dienste-Ordner:

package anotherstuff.NotAbstractClass; 

public final class NotAbstractClass extends TheAbstractClass implements ClassInterface{ 
    private String name = "Silent Bob"; 

    @Override 
    public String getClassName() { return name; } 

} 

Dann auf dem Mai n-Anwendung (das ist eigentlich ein Plugin in einer anderen Anwendung ist), möchte ich alle Klassen finden, die TheAbstractClass erweitern:

package stuff.TheApp; 

import java.util.ServiceLoader; 

public class TheApp { 
    private String name; 

    public final static TheApp INSTANCE = new TheApp(); 

    private TheApp() { 
     ServiceLoader<TheAbstractClass> serviceLoader = 
      ServiceLoader.load(TheAbstractClass.class); 
     for (TheAbstractClass class: serviceLoader) { 
      name = class.getClassName; 
     } 
} 

Meine Anwendung tut NotAbstractClass finden. Ich weiß, das da in der for-Schleife, ich class.getName() tun können, und es gibt mir anotherstuff.NotAbstractClass), sondern gibt den Fehler: java.lang.AbstractMethodError: stuff.TheAbstractClass.getClassName()Ljava/lang/String;

Ich bin ratlos. Irgendein Vorschlag? Vielen Dank, Pedro

+0

Haben Sie Ihre Dienste so definiert, dass sie gemäß https://docs.oracle.com/javase/tutorial/ext/basics/spi.html#register-service-providers registriert sind? – hotzst

+0

@hotzst, Tatsächlich habe ich.Ich weiß, dass es geladen ist, da ich in der for-Schleife "class.getName()" machen kann und es mir "anotherstuff.NotAbstractClass" gibt. –

Antwort

0

Nach der API für AbstractMethodError Sie diese:

Thrown when an application tries to call an abstract method. Normally, this error is caught by the compiler; this error can only occur at run time if the definition of some class has incompatibly changed since the currently executing method was last compiled.

einfach durch einen Blick auf den Code und Ihren Kommentar Ich sehe, dass dies nur zur Laufzeit geschehen konnte.

Wenn das der Fall ist, dann:

some class has incompatibly changed since the currently executing method was last compiled

ich Ihre Logik nach einigen Anpassungen in einer Java-kompatibelen Form getestet habe, und ich hatte keine Probleme. Das einzige, was zu geschehen scheint, ist eine Änderung in irgendeiner der Unterklassen von TheAbstractClass.

war eine andere Sache, die ich tat, die Abhängigkeiten unter Verwendung der Abhängigkeitsdateien in deklarieren: Ressourcen/META-INF/services:

Datei: < Voll Paket > .TheAbstractClass

Inhalt: <Komplettpaket> .NotAbstractClass

Danach hatte ich keine Probleme.

+1

Das scheint logisch und es ist wahrscheinlich der Fall. Allerdings ist "etwas Klasse" in meinen Gedanken etwas vage. Weder TheAbstractClass noch NotAbstractClass werden zur Laufzeit geändert, außer wenn ich etwas falsch verstehe? –

0

Es scheint, das Problem lag nicht im Code, sondern in der IDE (IntelliJ). Ich löschte alle zuvor gepackten Gläser und machte neue Gläser, ohne etwas zu ändern und es funktionierte magisch ... Also ist es ein IDE-Fehler und kein Sprachproblem! Danke @Joao und @hotzst dafür, dass sie sich Zeit zum Lesen nehmen. Am besten, Pedro

Verwandte Themen