使用javax.tool级联内存编译

Gel*_*Luo 10 java compiler-construction classpath classloader in-memory

Eclipse的JDT编译器提供了一个接口INameEnvironment,该接口定义了findType(...)使您能够进行级联编译的方法.奇怪的是我想知道是否有任何方法可以使用标准的JDK编译工具包来做到这一点?

注意,该场景是一个模板引擎,它在内存编译中为模板文件生成的类进行相互依赖,并且它无法预测您遇到模板文件的顺序,因此Foo可能需要先编译才能进行父Bar编译,因此你需要一个机制来进行级联编译,这意味着在编译期间Foo你需要生成另一个源Bar并首先编译它以便继续Foo编译:一些代码如下:

private NameEnvironmentAnswer findType(final String name) {
    try {
        if (!name.contains(TemplateClass.CN_SUFFIX)) {
            return findStandType(name);
        }

        char[] fileName = name.toCharArray();
        TemplateClass templateClass = classCache.getByClassName(name);

        // TemplateClass exists
        if (templateClass != null) {

            if (templateClass.javaByteCode != null) {
                ClassFileReader classFileReader = new ClassFileReader(templateClass.javaByteCode, fileName, true);
                return new NameEnvironmentAnswer(classFileReader, null);
            }
            // Cascade compilation
            ICompilationUnit compilationUnit = new CompilationUnit(name);
            return new NameEnvironmentAnswer(compilationUnit, null);
        }

        // So it's a standard class
        return findStandType(name);
    } catch (ClassFormatException e) {
        // Something very very bad
        throw new RuntimeException(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

men*_*ics 2

根据我们的评论对话,我认为答案是明确的:不,你不能使用 JDK 编译器来做到这一点。当它请求包时,它确实为您提供了一个钩子,但不是特定的类依赖项。

据我所知,您能得到的最接近的是:

这是一篇带有代码的好文章,但需要对其进行调整以处理内存类。具体来说,您所描述的问题是由该JavaFileManager.list(...)方法处理的。您必须在此处返回已缓存在内存中的 JavaFileObjects。您很可能需要创建ForwardingJavaFileManager本文中描述的子类 - 尽管进行了修改以处理您正在使用的缓存类。

你可以用它来编译一些东西。如果返回错误,请使用正则表达式找出缺少的内容。生成/编译缺少的代码后,重试编译原始代码。

注意:它确实在某些时候要求依赖类的 FQN 作为 ForwardingFileManager.list(...) 中的 packageName 参数。那时我还没有尝试返回课程。它可能不起作用,因为包不匹配,但也许会。