Java 注释不适用于外部 Jar 文件

Lig*_*num 3 java annotations jar file external

因此,我目前正在为我的命令行“操作系统”开发一个插件系统(插件是位于插件文件夹中的 jar 文件)。工作正常,但 API 不行。

我正在使用注释来获取插件主类和事件类。然而,它似乎没有找到我的注释。

这是我用来加载插件的:

public static void loadPlugin(File file)
{
    try
    {
        URL urlList[] =
        { new File("plugins/" + file.getName()).toURI().toURL() };
        URLClassLoader classLoader = new URLClassLoader(urlList);
        Class<?> pluginclass, eventclass = pluginclass = null;
        String name, version = name = null;
        Priority priority = Priority.NORMAL;

        String[] classes = Utils.getJarClasses(file, "plugin").toArray(new String[]
        {});

        for (String s : classes)
        {
            System.out.println(s);
            Class<?> c = classLoader.loadClass(s);
            Plugin p = c.getAnnotation(Plugin.class);
            EventHandler e = c.getAnnotation(EventHandler.class);

            if (p != null)
            {
                System.out.println("not null!");
                pluginclass = c;
                name = p.name();
                version = p.version();
                priority = p.priority();
            }

            if (e != null)
            {
                eventclass = c;
            }
        }

        switch (priority)
        {
        case NORMAL:
            plugins.add(new Class<?>[]
            { pluginclass, eventclass });
        case DEVELOPER_API:
            apis.add(new Class<?>[]
            { pluginclass, eventclass });
        }
        print("Loaded Plugin: " + name + " V" + version + " with priority " + priority.toString() + ".");
    } catch (Exception e)
    {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

它很好地打印出当前正在循环的类,但无论如何pe始终为 null。显然,版本名称也始终为空。

我的注释类已经有了@Retention(RetentionPolicy.RUNTIME),这就是我在这里问的主要原因。

我测试过一个类似的系统,只是没有使用 jar 文件(而是包内的类)并且运行良好。

提前致谢。

jcc*_*ero 5

可以解释所描述的行为的原因之一是您正在混合类加载器:只有当注释类和注释类型都由同一类加载器加载时,注释才会可见。这与使用 Reflection API 作为实际执行注释查找过程的机制有关。

在您的代码中,您使用自定义类加载器classLoader来从外部 jar 文件加载类,但是 和PluginEventHandler都是由运行您的方法的类加载器加载的loadPlugin

为了解决这个问题,我认为你可以提供运行该loadPlugin方法的类加载器作为自定义类加载器的父类加载器,如下所示:

URLClassLoader classLoader = new URLClassLoader(urlList, YourClass.class.getClassLoader());
Run Code Online (Sandbox Code Playgroud)

stackoverflow 中以前也报道过类似的行为。例如,请参阅此问题另一个问题的已接受答案。