设计API - 类加载麻烦(Groovy)

时间:2016-08-12 12:29:54

标签: javafx groovy

这是我第一次设计API。我有一个带有'plugins'文件夹的程序。我在JAR中打包的那个文件夹中制作了一个测试插件。在程序中我有一个Groovy类'Configuration',它应该加载插件。

Configuration.java

static void processConfiguration()
{
        File pluginDirectory=new File(PLUGINDIRECTORY)//it's 'plugins'
        if(!pluginDirectory.exists()) pluginDirectory.mkdir()
        File[] pluginfiles=pluginDirectory.listFiles()

        for(File f:pluginfiles)
        {
            if(f.name.endsWith('.jar'))
            {
                JarFile jar=new JarFile(f)

                for(JarEntry jarEntry:jar.entries())
                {
                    if(jarEntry.getName().endsWith('.class'))
                    {
                        //try loading the class   
                    }
                }


            }
        }
}

所以,我尝试在//try loading the class

进行这些操作

Class cl=ClassLoader.getSystemClassLoader().loadClass(jarEntry.name)

Class cl=new GroovyClassLoader().loadClass(jarEntry.name)

Class cl=Configuration.classLoader.loadClass(jarEntry.name)

Class cl=Class.forName(jarEntry.getName())

也试过替换 - jarEntry.name.replaceAll('/','.').replace('.class',''),但我认为它是自动完成的。 获得Class not found例外:

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: jace/plugins/JavaPlugin.class
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java_lang_ClassLoader$loadClass.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at jace.Configuration.processConfiguration(Configuration.groovy:87)
    at jace.Jace.start(Jace.java:56)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at  com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)

1 个答案:

答案 0 :(得分:1)

经过一番搜索和修补,我终于解决了。

首先,需要创建正确的URL列表;

其次,从jar中创建一个类列表;

第三,实例化GroovyClassLoader并给他所有的URL;

第四,从列表中加载类,检查它们是否实现了插件接口,然后实例化它们。

static void processConfiguration()
{
    File pluginDirectory=new File(PLUGINDIRECTORY)
    if(!pluginDirectory.exists()) pluginDirectory.mkdir()
    File[] pluginfiles=pluginDirectory.listFiles()
    URL[] urls=[]
    ArrayList<String> classes=new ArrayList<>()
    for(File f:pluginfiles)
        {
            if(f.name.endsWith('.jar'))
            {
                JarFile jar=new JarFile(f)
                URL url=new URL('jar:file:'+PLUGINDIRECTORY+'/'+f.name+'!/')
                urls+=url
                jar.entries().each {if(it.name.endsWith('.class'))classes.add(it.name) }
            }
        }

//        println(gcl.loadedClasses)
        GroovyClassLoader groovyClassLoader=new GroovyClassLoader()
        urls.each {groovyClassLoader.addURL(it)}
//        println(classes)
        classes.each {
            Class cl=groovyClassLoader.loadClass(it.replaceAll('/','.').replace('.class',''))
            Class[] interfaces=cl.getInterfaces()
            if(interfaces.contains(Plugin.class))
            {
                Object instance=cl.newInstance()
                if(interfaces.contains(SuggestionPlugin.class))
                {
                    SuggestionProcessor.suggestionPlugins.add(instance as SuggestionPlugin)
                }
                Constructor[] constructors=cl.getConstructors()
                println("Loaded a plugin $cl.simpleName")
            }
    }
}