【发布时间】:2014-05-16 05:37:04
【问题描述】:
我正在编写一个程序,它允许用户在文本区域中键入 java 代码,然后对其进行编译并将其作为一种“插件”加载到程序中。我目前能够编译 .java 文件并加载外部类,但我无法毫无错误地加载/实例化用户编写的内部类。目前这是我用来加载外部类的,这段代码有效,我可以轻松地使用外部类而没有任何复杂性。 (为了更好的可读性,我做了一些编辑,如果你发现一个错字告诉我)
private ArrayList<String> execute(ArrayList<String> fileNames) {
ArrayList<String> successStories = new ArrayList();
ArrayList<Class<?>> eventHandlers = new ArrayList();
// Load all classes first...
for (int i = 0; i < fileNames.size(); i++) {
Class<?> clazz = loadClassByName2(fileNames.get(i));
if (EventHandler.class.isAssignableFrom(clazz)) {
eventHandlers.add(clazz);
successStories.add(fileNames.get(i));
} else if (InterfaceInnerClass.class.isAssignableFrom(clazz)) {
successStories.add(fileNames.get(i));
} else {
System.out.println(clazz.getName() + " couldn't be loaded");
}
}
// Then instantiate the handlers.
for (int i = 0; i < eventHandlers.size(); i++) {
try {
Object obj = eventHandlers.get(i).newInstance();
if (obj instanceof EventHandler) {
EventHandler EH = (EventHandler)obj;
EH.name = EH.getClass().getSimpleName();
CmdEvents.addEvent(EH);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return successStories;
}
public static Class<?> loadClassByName2(String name) {
try {
// My program sets up classpath environment variables so "./" is all that is needed as the URL
URLClassLoader classLoader = new URLClassLoader(
new URL[] { new File("./").toURI().toURL() });
// Load the class from the classloader by name....
Class<?> c = classLoader.loadClass("plugins.event_handlers." + name);
classLoader.close();
return c;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
文件名的原始列表是从 GUI 发送的,其中列出了插件目录中的每个 .class 文件。他们的用户选择他们想要加载的类,单击一个按钮并将这些文件名发送到这些方法。在这段代码中,EventHandler 是一个类,您将在下面看到,InterfaceInnerClass 只是一个用作标记以确保没有任何严重问题的接口,而 CmdEvents 是我的程序中用于管理这些“插件”类的控制台命令。就像我上面说的,这段代码适用于外部类,问题是当我尝试加载内部类时。我的 EventHandler 抽象类的代码如下。
public abstract class EventHandler {
public String name; // Don't mind this being public, I have my reasons for this.
public abstract void execute(String input);
public abstract boolean condition(String input);
}
我的程序的工作方式是,它从用户那里接收一个字符串,然后调用条件(字符串),如果它返回真,它就调用执行(字符串)。我写了一些测试代码来试用我的加载器,如下所示。
package plugins.event_handlers;
public class Test_Handler extends events.EventHandler {
public void execute(String input) {
System.out.println("Testing...");
TestInner inner = new TestInner();
inner.test();
System.out.println("Did it work?");
}
public boolean condition(String input) {
return input.contains("testinput");
}
public class TestInner implements events.InterfaceInnerClass {
public TestInner() {
System.out.println("The inner works!");
}
public void test() {
System.out.println("Inner class has been tested");
}
}
}
我运行我的程序,同时选择 Test_Handler.class 和 Test_Handler$TestInner.class,然后单击按钮。当该方法返回一个 ArrayList 或成功加载的类时,它同时返回外部类和内部类。但是,当我运行程序并将“testinput”传递给条件和执行方法时,这是我的输出。
测试中...线程“Execute_Thread_Test_Handler”中的异常 java.lang.NoClassDefFoundError: 插件/event_handlers/Test_Handler$TestInner 在 plugins.event_handlers.Test_Handler.execute(Test_Handler.java:11) 在 events.ThreadEventExecutor.run(ThreadEventExecutor.java:20) 原因: java.lang.ClassNotFoundException: plugins.event_handlers.Test_Handler$TestInner 在 java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) 在 java.net.URLClassLoader.findClass(未知来源)在 java.lang.ClassLoader.loadClass(Unknown Source) 在 java.lang.ClassLoader.loadClass(Unknown Source) ... 2 更多
我想要它打印的是
测试... 内功! 内部类已经过测试 成功了吗?
最后我的问题是,如何使上述代码工作?我不想让我的用户编写自己的类加载器等来加载内部/单独的类(因为并非我的所有用户都一定会在编码方面表现出色)所以我需要能够在没有引用的情况下引用内部类类型代码爆炸。
【问题讨论】:
标签: java inner-classes urlclassloader