我正在使用Java编译器API动态编译Java源代码。我生成的源文件继承自com.example.BaseClass,它只是一个普通的类,不是动态生成的。生成的 Java 源代码如下所示:
public class Foo implements com.example.BaseClass
{
@Override
public Integer getAnswer(com.example.Context context) throws Exception
{
return ...;
}
}
在 IDE 中运行时一切正常,但是在打包到 Springboot jar 中后,我的 com.example.BaseClass 被移动到 BOOT-INF/classes/com.example.BaseClass。动态编译时,我现在得到:
/Foo.java:1: error: package com.example does not exist
public class Foo implements com.example.BaseClass
^
我尝试更改编译器的类加载器,以便编译器将在 BOOT-INF/类中进行搜索。
ClassLoader before = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(new CustomClassloader(before));
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
Thread.currentThread().setContextClassLoader(before);
但是,调试显示我的 CustomClassloader.loadClass(字符串名称( 方法从未被调用。更多的调试显示 compiler.getClass((.getClassloader(( 返回
java.net.FactoryURLClassLoader@39a5ae48
因此,编译器实例不使用自定义类加载器。如何让编译器使用我的自定义类加载器?当然,也欢迎解决编译问题的更好解决方案:-(。
关于Java标准编译器如何进行查找,有一些奇怪的问题,它并不总是正确地解析出正在运行的类路径。 无论如何,它使用 JavaFileManager.list 调用来执行该解决方案。
它会在尝试查找基类的过程中至少调用它 4 次。 覆盖 ForwardingJavaFileManager 并将其传递给 getTask 并让它查找资源并返回它。
或者,您可以使用 Janino in-momeory 编译器库,该库在内存文件系统中设置一个假的(没有编译到磁盘(,并且仍然使用 plaform 编译器并为您整理所有这些类路径废话。