如何让JavaCompiler使用提供的类加载器查找类?

如何让JavaCompiler使用提供的类加载器查找类?,java,javac,java-compiler-api,Java,Javac,Java Compiler Api,我使用的是一篇关于如何在运行时编译和使用Java类的老IBM博客文章。代码大多工作得很好(顺便说一句,写得很好),但不幸的是,它在我的一个用例中不起作用,其中正在编译的类引用另一个类,该类只能由提供给CharSequenceCompiler(从博客文章中)的类加载器提供,而不能由应用程序类加载器提供 更具体地说,我传递给CharSequenceCompiler的类加载器是一个OSGi类加载器 拥有这个类加载器的包可以找到并返回一个类,比如Foo class Foo { public static

我使用的是一篇关于如何在运行时编译和使用Java类的老IBM博客文章。代码大多工作得很好(顺便说一句,写得很好),但不幸的是,它在我的一个用例中不起作用,其中正在编译的类引用另一个类,该类只能由提供给
CharSequenceCompiler
(从博客文章中)的类加载器提供,而不能由应用程序类加载器提供

更具体地说,我传递给
CharSequenceCompiler
的类加载器是一个OSGi类加载器

拥有这个类加载器的包可以找到并返回一个类,比如
Foo

class Foo { public static String FOO = "F"; }
我知道如果你使用
classLoader.findClass(“Foo”)因为当我从调试器调用它时,它会工作

现在,从我在运行时编译的类,比如说
Dynamic
,我需要使用
Foo
。。。因此,我将
Foo
捆绑包的类加载器传递给
CharSequenceCompiler
,然后要求它编译
动态

class Dynamic { public static String D = Foo.FOO; }
这会导致以下错误:

error: cannot find symbol
Foo.FOO;
^
symbol:   variable Foo
如果
Foo
CharSequenceCompiler
在同一个项目中,那么它可以工作。。。因此,从正确的类装入器装入类显然是个问题

我已经调试这段代码好几天了(或者晚上,tbh),但我不知道为什么我提供给编译器的类加载器从来没有被问及这个类

FileManager
被要求
list()
列出每个包中的资源,但即使我使用调试器手动将
FileObject
添加到返回的列表中,它仍然无法工作


由于调试器无法穿透javac内部使用的本机类,因此我无法在这方面继续。。。有没有人对编译器有一些内部知识,可以解释发生了什么事?

使用真正的java编译器有什么好处。字节码生成选项不适合您吗


例如:或

经过一场漫长的战斗,我终于明白了这一点

我发现的几乎所有基于java.tools API的内存中java编译器实现的问题是,即使它们允许您传入
ClassLoader
来加载您编译的类,ClassLoader也只用于加载新类,但不能获取可在编译的Java代码中使用的类

由于这个原因,我的用例(如问题中所解释的)将无法与IBM博客文章中显示的代码(或类似的其他项目)一起使用

如果希望由
ClassLoader
加载给编译器的类(在应用程序
ClassLoader
中不可见)可供正在编译的类使用,则需要两件事

首先,类加载器类必须是可枚举的。然后,
JavaFileManager
可以使用它正确地实现
list()
方法。对于每个包,此方法必须返回
ClassLoader
可以在需要时加载的类

其次,您需要能够从
ClassLoader
资源构建
JavaFileObject
s,因为这是您必须返回的对象类型。为此,您需要向类加载器询问类的字节码流(使用
getResourceAsStream(“class.class”)
),然后创建一个
JavaFileObjectImpl
。基本上,这是一个伪代码:

fileObject = new JavaFileObjectImpl( pathMinusDotClass, JavaFileObject.Kind.CLASS );
fileObject.openOutputStream()
    .write( classLoader.getInputStream( path ) );
现在,编译器将知道它可以从提供的类加载器中加载哪些类,并且一切正常


我在我的上的一个真正的编译器中实现了这一点,该编译器尚未发布,但我计划很快完成(于2016年7月编写)。。。它的外壳中包含一个Java命令,可以运行任意Java代码,这就是我需要让它工作的原因。

谢谢,但我想从源代码中获取字节码。顺便说一句,在我的例子中,类加载器类是可枚举的,因为OSGi支持捆绑式加载。。。在OSGi之外,除了检查JAR之外,没有安全的方法可以让类加载器加载所有的类(因此,如果您从其他东西加载类,您就被卡住了)。