2017-10-21 2 views
0

Ich versuche, ein Plugin-System für meine Anwendung zu implementieren, dessen Code meine Plugin-Klasse erweitert, um benutzerdefinierte Funktionen zu definieren.Wie .class aus dem Arbeitsverzeichnis zur Laufzeit von jar laden?

Dieser Code eine Klasse aus einem Glas zu laden, im selben Verzeichnis wie die .jar der Anwendung funktioniert gut:

if(pluginName.endsWith(".jar")) 
{ 
    JarFile jarFile = new JarFile(pluginName); 
    Enumeration jarComponents = jarFile.entries(); 

    while (jarComponents.hasMoreElements()) 
    { 
     JarEntry entry = (JarEntry) jarComponents.nextElement(); 
     if(entry.getName().endsWith(".class")) 
     { 
      className = entry.getName(); 
     } 
    } 

    File file = new File(System.getProperty("user.dir")+"/"+pluginName); 
    URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()}); 

    Class newClass = Class.forName(className.replace(".class", ""), true, loader); 
    newPlugin = (Plugin) newClass.newInstance(); 
} 

in der richtigen Antwort führt aus:

benpalmer$ java -jar assignment.jar test_subproject.jar 
- INFO: Add new plugin: source.com 

Das Problem ist, ich möchte auch dem Benutzer die Option zur Verfügung stellen, eine .class-Datei stattdessen, da das ist realistisch alles, was in einem. Jar für die Zwecke meines Plugin-System gepackt ist.

else if(pluginName.endsWith(".class")) 
{ 
    File file = new File(System.getProperty("user.dir")+"/"+pluginName); 
    URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()}); 

    Class newClass = Class.forName(className.replace(".class", ""), true, loader); 
    newPlugin = (Plugin) newClass.newInstance(); 
} 
... exception handling 

, die in den folgenden Ergebnissen:

benpalmer$ java -jar assignment.jar TestPlugin.class 
SEVERE: Error: Plugin class not found. Class name: 
java.lang.ClassNotFoundException: 
    at java.lang.Class.forName0(Native Method) 
    at java.lang.Class.forName(Class.java:348) 
    at newsfeed.model.Plugin.loadClassFromJarFile(Plugin.java:144) 
    at newsfeed.controller.NFWindowController.initPlugins(NFWindowController.java:81) 
    at newsfeed.controller.NewsFeed$1.run(NewsFeed.java:20) 
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756) 
    at java.awt.EventQueue.access$500(EventQueue.java:97) 
    at java.awt.EventQueue$3.run(EventQueue.java:709) 
    at java.awt.EventQueue$3.run(EventQueue.java:703) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:726) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) 

ich den obigen Code und viele Variationen von Pfadnamen versucht haben/andere Optionen, aber ClassNotFoundException jedes Mal bekommen. Hatte ursprünglich Probleme beim Laden der Jars, aber mit dem voll qualifizierten Pfad behoben, dass ich jetzt die Klassen nicht laden kann.

Irgendwelche Ideen? :)

+0

sollten Sie wirklich verwenden [ServiceLoader] (https://docs.oracle.com/javase/9/docs/api/java/util/ServiceLoader.html) dafür. – VGR

Antwort

0

Sah meine Frage wieder und erkannte, dass ich vergessen hatte, eine Lösung zu posten, die ich zu meinem Problem fand. Ich hoffe, dass dies jemandem in der Zukunft hilft, da es das einzige Arbeitsbeispiel ist, das ich je für meine Situation gefunden habe - ein Problem mit der Universitätsproblematik. Ich kann nicht glauben, dass es so einfach war:

byte[] classData = Files.readAllBytes(Paths.get(fileName)); 
Class<?> cls = defineClass(null, classData, 0, classData.length); 
return (PluginClassName)cls.newInstance(); 
1

Dies ist eine Funktion von URLClassLoader funktioniert mit Verzeichnissen von Klassen (Sie können davon ausgehen, .jar als gepacktes Verzeichnis).

Die constructor Sie verwenden den folgenden javadoc

für die angegebene URLs mit dem Standard-Delegation Eltern Classloader einen neuen URLClassLoader Konstruiert. Die URLs werden nach der ersten Suche im übergeordneten Klassenladeprogramm in der Reihenfolge durchsucht, die für Klassen und Ressourcen angegeben wurde. Jede URL, die mit einem '/' endet, wird für ein Verzeichnis angenommen. Andernfalls wird angenommen, dass sich die URL auf eine JAR-Datei bezieht, die nach Bedarf heruntergeladen und geöffnet wird.

Wenn Sie unbedingt wollen, für jede einzelne Klasse Classloader erstellen Sie SecureClassLoader und definieren neue Klasse Subklassen manuell mit defineClass Methode in Betracht ziehen sollten.

The basics of Java class loaders Artikel sollte Ihnen helfen.

+0

Vielen Dank für Ihren Rat hier. Aufgrund der Schwierigkeit, diese und zeitliche Beschränkungen zu implementieren, habe ich mich entschieden, eine .class-Datei nicht zuzulassen. –

Verwandte Themen