Why can't the Java class loader find my interface?

核能气质少年 提交于 2019-12-11 02:13:40

问题


In the code below I generate a class dynamically using sun.tools.javac.Main. I will create a new instance of this class using Reflection. The problem is, I want to avoid using Reflection to invoke the method I defined for this class, so I created a ProxyInvoker that references an interface I defined in my project. In order for the classloader to see this, I add the classpath to the Executable interface to my classloader. I still get an error during the 'compilation' step that says that my interface was not found.

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;

    }

}

回答1:


Here is a working version of your code:

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;

    }

}

The main changes: classloader and compilation parts were wrong.



来源:https://stackoverflow.com/questions/4210346/why-cant-the-java-class-loader-find-my-interface

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!