1

我曾经JavaCompiler编译过一个即时生成的类。编译任务成功。然后我尝试使用加载编译的类Class.forName("MyClass");它以 ClassNotFoundException 失败。这样做是否存在已知问题?

package com.amir.method;

import java.io.*;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import javax.tools.*;

public class MethodGenerator {

    private final static MethodGenerator INSTANCE = new MethodGenerator();

    private MethodGenerator() {
    }

    public static MethodGenerator get() {
        return INSTANCE;
    }


    public static void main(String[] args) {

        final Class<?> clz = MethodGenerator.get().compile("Foo", "doIt"); //<- args ignored for now

    }

    public Class compile(final String className,
                         final String methodName) {
        try {
            return doCompile(className, methodName);
        } catch(final Exception e) {
            throw new RuntimeException(this.toString(), e);
        }

    }

    private Class doCompile(final String className,
                            final String methodName) throws IOException, ClassNotFoundException {

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

        StringWriter writer = new StringWriter();
        PrintWriter out = new PrintWriter(writer);
        out.println("public class HelloWorld {");
        out.println("  public static void main(String args[]) {");
        out.println("    System.out.println(\"This is in another java file\");");
        out.println("  }");
        out.println("}");
        out.close();

        final JavaFileObject file = new JavaSourceFromString("HelloWorld", writer.toString());
        final Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
        final String classPath = System.getProperty("java.class.path") + File.pathSeparator;
        final String bootClassPath = System.getProperty("sun.boot.class.path") + File.pathSeparator;
        final List<String> options = new ArrayList<String>();
        options.add("-classpath");
        final StringBuilder builder = new StringBuilder();
        builder.append(classPath);
        builder.append(bootClassPath);
        final URLClassLoader urlClassLoader = (URLClassLoader) ClassLoaderResolver.getClassLoader();
        for (final URL url : urlClassLoader.getURLs()) {
            builder.append(url.getFile()).append(File.pathSeparator);
        }
        final int lastIndexOfColon = builder.lastIndexOf(File.pathSeparator);
        builder.replace(lastIndexOfColon, lastIndexOfColon + 1, "");
        options.add(builder.toString());

        final JavaCompiler.CompilationTask task = compiler.getTask(null, null, diagnostics, options, null, compilationUnits);

        boolean success = task.call();

        if(success) {
            final Class<?> cls = Class.forName("HelloWorld", true, urlClassLoader);
            return cls;
        }

        return null;

    }

    class JavaSourceFromString extends SimpleJavaFileObject {
        final String code;

        JavaSourceFromString(String name, String code) {
            super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension),Kind.SOURCE);
            this.code = code;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return code;
        }
    }

}
4

1 回答 1

0

尝试使用编译后加载类,Thread.currentThread().getContextClassLoader().loadClass("com.ur.class");

找到这个...检查这是否有帮助..

// Create a new custom class loader, pointing to the directory that contains the compiled
// classes, this should point to the top of the package structure!
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
// Load the class from the classloader by name....
Class<?> loadedClass = classLoader.loadClass("com.ur.class");
// Create a new instance...
Object obj = loadedClass.newInstance();
// Santity check
if (obj instanceof com.ur.class) {
    // code here ...
}

有关更多信息,请参阅:如何动态编译和加载外部 java 类?

于 2014-11-06T18:06:26.817 回答