java - 为什么 Java 类加载器找不到我的接口(interface)?

标签 java classloader

在下面的代码中,我使用 sun.tools.javac.Main 动态生成一个类。我将使用反射创建此类的新实例。问题是,我想避免使用 Reflection 来调用我为此类定义的方法,因此我创建了一个 ProxyInvoker 来引用我在项目中定义的接口(interface)。为了让类加载器看到这一点,我将类路径添加到类加载器的可执行接口(interface)中。在“编译”步骤中我仍然收到错误消息,提示找不到我的接口(interface)。

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class MyClassGenerator {

    static final String generatedClassName = "TestHello_" + System.currentTimeMillis();
    static final String javaFileName = generatedClassName + ".java";

    static URLClassLoader classLoader;

    public static void main(final String args[])
            throws MalformedURLException {
        final ProxyInvoker proxy = new ProxyInvoker();
        generateClass();
        loadExecutableInterface();
        if (compileClass()) {
            System.out.println("Running " + generatedClassName + ":\n\n");
            final Executable ex = createExecutable();
            ex.execute();
        }
        else {
            System.out.println(javaFileName + " is bad.");
        }
    }

    public static void loadExecutableInterface()
            throws MalformedURLException {

        final File file = new File("."); // <-- the directory where the generated java class is defined
        final File file2 = new File("src"); // <-- the directory where interface Executable is defined

        try {
            classLoader = URLClassLoader.newInstance(new URL[] { file.toURI().toURL(), file2.toURI().toURL() });
            try {
                classLoader.loadClass("Executable");
            }
            catch (final ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        catch (final MalformedURLException e) {
            e.printStackTrace();
        }
        System.out.println(file.toURI().toURL());
        System.out.println(file2.toURI().toURL());

    }

    public static void generateClass() {
        try {
            final FileWriter aWriter = new FileWriter(javaFileName, true);
            aWriter.write("public class " + generatedClassName + " implements Executable {");
            aWriter.write("\n");
            aWriter.write("\n");
            aWriter.write("    public void invoke() {");
            aWriter.write("        System.out.println(\"Hello World!\");");
            aWriter.write("    }");
            aWriter.write("\n");
            aWriter.write("}");
            aWriter.flush();
            aWriter.close();
        }
        catch (final Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean compileClass() {
        final String[] source = { new String(javaFileName) };
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new sun.tools.javac.Main(baos, source[0]).compile(source);
        System.out.print(baos.toString());
        return (baos.toString().indexOf("error") == -1);
    }

    public static Executable createExecutable() {

        Executable instance = null;

        try {
            final Class<?> genClass = Class.forName(generatedClassName, true, classLoader);
            instance = (Executable) genClass.newInstance();
        }
        catch (final Exception e) {
            e.printStackTrace();
        }

        return instance;

    }
}

class ProxyInvoker {

    Executable myExecutable;

    public void runIt() {

        final Executable myExecutable;

    }

}

最佳答案

这是您的代码的工作版本:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class MyClassGenerator {

    static final String generatedClassName = "TestHello_" + System.currentTimeMillis();
    static final String javaFileName = generatedClassName + ".java";

    static URLClassLoader classLoader;

    public static void main(final String args[])
            throws MalformedURLException {
        generateClass();
        loadExecutableInterface();
        if (compileClass()) {
            System.out.println("Running " + generatedClassName + ":\n\n");
            final Executable ex = createExecutable();
            ex.execute();
        }
        else {
            System.out.println(javaFileName + " is bad.");
        }
    }

    public static void loadExecutableInterface()
            throws MalformedURLException {

        final File file = new File("."); // <-- the directory where the generated java class is defined

        try {
            classLoader = URLClassLoader.newInstance(new URL[] { file.toURI().toURL() }, Executable.class.getClassLoader());
            try {
                classLoader.loadClass("Executable");
            }
            catch (final ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        catch (final MalformedURLException e) {
            e.printStackTrace();
        }
        System.out.println(file.toURI().toURL());

    }

    public static void generateClass() {
        try {
            final FileWriter aWriter = new FileWriter(javaFileName, true);
            aWriter.write("public class " + generatedClassName + " implements Executable {");
            aWriter.write("\n");
            aWriter.write("\n");
            aWriter.write("    public void execute() {");
            aWriter.write("        System.out.println(\"Hello World!\");");
            aWriter.write("    }");
            aWriter.write("\n");
            aWriter.write("}");
            aWriter.flush();
            aWriter.close();
        }
        catch (final Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean compileClass() {
        final String[] source = { "-classpath", "target/classes", javaFileName };
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new sun.tools.javac.Main(baos, source[0]).compile(source);
        System.out.print(baos.toString());
        return (baos.toString().indexOf("error") == -1);
    }

    public static Executable createExecutable() {

        Executable instance = null;

        try {
            final Class<?> genClass = Class.forName(generatedClassName, true, classLoader);
            instance = (Executable) genClass.newInstance();
        }
        catch (final Exception e) {
            e.printStackTrace();
        }

        return instance;

    }

}

主要变化:类加载器和编译部分是错误的。

关于java - 为什么 Java 类加载器找不到我的接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4210346/

相关文章:

java - 创建重新检查 if 语句

java.lang.NoSuchMethodError,两个类都在同一个 JAR 中!

java - 由于 JAXBClassLoader 中的泄漏而导致 PermGen 错误

java - mapreduce 作业的进度

c# - 如何编写具有固定长度和多个元素的正则表达式

java - 在 Hibernate 的@Formula 中使用 NATURAL JOIN

java - 类加载器行为 : java -cp jars vs adding maven dependency in pom

java - 如何打印命令 "mvn compile"的类加载模式?

java - SLF4J-API 类加载如何优先考虑绑定(bind)而不是虚拟?

java - 在 ViewPager 中使用多个图像