Java JavaCompiler.run()也编译匿名类

Java JavaCompiler.run()也编译匿名类,java,classloader,dynamic-loading,javacompiler,Java,Classloader,Dynamic Loading,Javacompiler,我正在尝试动态加载文本文件并编译它们 File file = new File("Files/"+fileName+".java"); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); compiler.run(null, null, errStream, file.getAbsolutePath()); 随后,我将加载编译后的.class文件: public Class loadStrategyClass(File

我正在尝试动态加载文本文件并编译它们

File file = new File("Files/"+fileName+".java");
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, errStream, file.getAbsolutePath());
随后,我将加载编译后的.class文件:

 public Class loadStrategyClass(File strategyClassFile) throws IOException
    {
        FileChannel roChannel = new RandomAccessFile(strategyClassFile, "r").getChannel();
        ByteBuffer buffer = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, (int)roChannel.size());

        return defineClass(strategyClassFile.getName(), buffer, (ProtectionDomain)null);
    }
我目前遇到两个问题: 第一个是我加载的.java文件是否包含匿名类。JavaCompiler类似乎不会编译这些。 线程“main”java.lang.IllegalAccessException中出现异常:Class Loader.ClassLoader无法使用修饰符访问类文件.myname.myclass$1的成员

第二点: 有时我会因为NoClassDefFoundError而出错: 线程“main”java.lang.NoClassDefFoundError中出现异常:Files/myname/myclass
尽管其他类将正确加载并且.class文件位于该路径中。

显然,您的
loadStrategyClass
是在自定义
类加载器中定义的。问题是,仅仅对您感兴趣的类调用一次
defineClass
是不够的,您的类加载器必须能够根据需要解析类,通常是通过实现
findClass
,这样JVM就可以解析依赖项,比如内部类

您没有指定如何获取
loadStrategyClass
方法的
strategyClassFile
参数。由于您在没有任何选项的情况下运行编译器,我想您只需查找相对于源文件的文件。要解析其他依赖项,需要知道类目录的实际根。当您定义类文件的存储位置时,它会变得更容易,例如

// customize these, if you want, null triggers default behavior
DiagnosticListener<JavaFileObject> diagnosticListener = null;
Locale locale = null;

JavaCompiler c = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm
    = c.getStandardFileManager(diagnosticListener, locale, Charset.defaultCharset());

// define where to store compiled class files - use a temporary directory
Path binaryDirectory = Files.createTempDirectory("compile-test");
fm.setLocation(StandardLocation.CLASS_OUTPUT,
               Collections.singleton(binaryDirectory.toFile()));

JavaCompiler.CompilationTask task = c.getTask(null, fm,
    diagnosticListener, Collections.emptySet(), Collections.emptySet(),
    // to make this a stand-alone example, I use embedded source code
    Collections.singleton(new SimpleJavaFileObject(
        URI.create("string:///Class1.java"), Kind.SOURCE) {
            public CharSequence getCharContent(boolean ignoreEncodingErrors) {
                return "package test;\npublic class Class1 { public class Inner {} }";
            }
        }));
if(task.call()) try {
    URLClassLoader cl = new URLClassLoader(new URL[]{ binaryDirectory.toUri().toURL() });
    Class<?> loadedClass = cl.loadClass("test.Class1");
    System.out.println("loaded "+loadedClass);
    System.out.println("inner classes: "+Arrays.toString(loadedClass.getClasses()));
} catch(ClassNotFoundException ex) {
    ex.printStackTrace();
}

如果您使用它来动态绑定插件或模块,您可以扩展搜索以查找实现特定接口或具有特定注释的结果类。

是否需要特定java代码,或者是否可以使用嵌入式脚本来执行像nashorn这样的操作?按您所指的语言环境:?这似乎是一个地理区域,这似乎是错误的;它链接到所使用的所有其他类型。如果底层编译器支持,
Locale
参数允许本地化错误消息。谢谢。这是如何工作的:)。我在网上找不到任何描述我想要什么的东西。
public static Class<?> compile(
    DiagnosticListener<JavaFileObject> diagnosticListener,
    Locale locale, String sourceFile) throws IOException, ClassNotFoundException {

    JavaCompiler c = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fm
        = c.getStandardFileManager(diagnosticListener, locale, Charset.defaultCharset());

    // define where to store compiled class files - use a temporary directory
    Path binaryDirectory = Files.createTempDirectory("compile-test");
    fm.setLocation(StandardLocation.CLASS_OUTPUT,
                   Collections.singleton(binaryDirectory.toFile()));

    JavaCompiler.CompilationTask task = c.getTask(null, fm,
        diagnosticListener, Collections.emptySet(), Collections.emptySet(),
        fm.getJavaFileObjects(new File(sourceFile)));
    if(task.call()) {
        Class<?> clazz = null;
        URLClassLoader cl = new URLClassLoader(new URL[]{binaryDirectory.toUri().toURL()});
        for(JavaFileObject o: fm.list(
            StandardLocation.CLASS_OUTPUT, "", Collections.singleton(Kind.CLASS), true)) {

            String s = binaryDirectory.toUri().relativize(o.toUri()).toString();
            s = s.substring(0, s.length()-6).replace('/', '.');
            clazz = cl.loadClass(s);
            while(clazz.getDeclaringClass() != null) clazz = clazz.getDeclaringClass();
            if(Modifier.isPublic(clazz.getModifiers())) break;
        }
        if(clazz != null) return clazz;
        throw new ClassNotFoundException(null,
            new NoSuchElementException("no top level class generated"));
    }
    throw new ClassNotFoundException(null,
        new NoSuchElementException("compilation failed"));
}