简体   繁体   English

如何更改 getSystemJavaCompiler 的类加载器

[英]How can I change classloader of getSystemJavaCompiler

I am dynamically compiling Java sources using the Java compiler API.我正在使用 Java 编译器 API 动态编译 Java 源代码。 My generated source files inherit from com.example.BaseClass, which is just a normal class, not dynamically generated.我生成的源文件继承自com.example.BaseClass,它只是一个普通的类,不是动态生成的。 The generated Java sources look like this:生成的 Java 源代码如下所示:

public class Foo implements com.example.BaseClass
{
    @Override
    public Integer getAnswer(com.example.Context context) throws Exception
    {
        return ...;
    }
}

All works fine when running in IDE, but after packaging into a Springboot jar, my com.example.BaseClass is moved to BOOT-INF/classes/com.example.BaseClass.在 IDE 中运行时一切正常,但在打包到 Springboot jar 后,我的 com.example.BaseClass 被移动到 BOOT-INF/classes/com.example.BaseClass。 When dynamically compiling I now get:动态编译时,我现在得到:

/Foo.java:1: error: package com.example does not exist 
public class Foo implements com.example.BaseClass
                                       ^

I try to change the classloader of the compiler so that the compiler will search in BOOT-INF/classes.我尝试更改编译器的类加载器,以便编译器在 BOOT-INF/classes 中搜索。

    ClassLoader before = Thread.currentThread().getContextClassLoader();
    Thread.currentThread().setContextClassLoader(new CustomClassloader(before));
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    Thread.currentThread().setContextClassLoader(before);

However, debugging shows that my CustomClassloader.loadClass(String name) method is never called.但是,调试显示我的 CustomClassloader.loadClass(String name) 方法从未被调用。 More debugging showed that compiler.getClass().getClassloader() returns更多调试表明 compiler.getClass().getClassloader() 返回

java.net.FactoryURLClassLoader@39a5ae48

So, the CustomClassloader is not used by the Compiler instance.因此, Compiler 实例不使用 CustomClassloader。 How can I get the Compiler to use my CustomClassloader?如何让编译器使用我的 CustomClassloader? Better solutions for solving the compiling issue are also welcome ofcourse :-).当然也欢迎更好的解决编译问题的解决方案:-)。

There are some oddities about how the java standard compiler does lookups and it doesn't always resolve out of the running class path correctly. java 标准编译器如何进行查找有一些奇怪的地方,并且它并不总是正确解析正在运行的类路径。 Anyway, it does that resolution using the JavaFileManager.list call.无论如何,它使用JavaFileManager.list调用来解决这个问题。

It will call it at least 4 times in the process of trying to look up your base class.在尝试查找基类的过程中,它至少会调用 4 次。 Override a ForwardingJavaFileManager and pass that into getTask and have it lookup the resource and return it.覆盖ForwardingJavaFileManager并将其传递给getTask并让它查找资源并返回它。

Alternately, you could use the Janino in-momeory compiler library which sets up a fake in memory file system ( no compiling to disk ) and still uses the plaform compiler and sorts out all this classpath nonsense for you.或者,您可以使用Janino in-momeory 编译器库,它在内存文件系统中设置一个伪造的文件系统(没有编译到磁盘),并且仍然使用平台编译器并为您整理出所有这些类路径废话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM