사용자가 자바 코드를 텍스트 영역에 입력 한 다음 컴파일하여 "플러그인"의 일종으로 프로그램에로드 할 수있는 프로그램을 작성 중입니다. 현재 .java 파일을 컴파일하고 외부 클래스를로드 할 수 있지만 오류없이 사용자가 작성한 내부 클래스를로드/인스턴스화 할 수는 없습니다. 현재 이것은 외부 클래스를로드하는 데 사용되며이 코드는 작동하며 합병증없이 외부 클래스를 쉽게 사용할 수 있습니다.ClassLoader를 사용하여 내부 클래스로드하기
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;
}
}
파일 이름의 원래 목록이 나열된 플러그인 디렉토리에있는 모든의 .class 파일이있는 GUI로부터 전송 (당신이 오타가 말해 나는 경우 나, 더 나은 가독성을 위해 약간의 편집을했다). 사용자는로드하려는 클래스를 선택하고 버튼을 클릭 한 다음 해당 파일 이름을이 메소드에 보냅니다. 이 코드에서 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);
}
내 프로그램이 작동하는 방법은, 그 다음 (문자열) 상태를 호출하고 true를 돌려주는 경우, 그것은 (String)를 실행 호출, 사용자로부터 문자열을 받으면에. 다음과 같이 내 로더를 시험해 볼 테스트 코드를 작성했습니다.
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"을 조건에 전달하고 메서드를 실행하면 이것이 내 결과입니다.
Testing... Exception in thread "Execute_Thread_Test_Handler" java.lang.NoClassDefFoundError: plugins/event_handlers/Test_Handler$TestInner at plugins.event_handlers.Test_Handler.execute(Test_Handler.java:11) at events.ThreadEventExecutor.run(ThreadEventExecutor.java:20) Caused by: java.lang.ClassNotFoundException: plugins.event_handlers.Test_Handler$TestInner at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 2 more
나는 인쇄에 걸려 어떻게 내가 위의 코드 작업을 어떻게, 그래서 결국 내 질문
입니까? 나는 내 사용자가 자신의 클래스 로더를 작성하여 내부/별도의 클래스를로드하지 않아도되도록하고 싶지는 않습니다. 왜냐하면 (모든 사용자가 필연적으로 코딩 할 때 놀랄만 한 것은 아니기 때문입니다.) 그래서 내부 클래스 유형을 참조 할 수 있어야합니다. 코드가 날아간다.Testing... The inner works! Inner class has been tested Did it work?