Java注解处理:使用其他注解处理器编辑由注解处理器创建的文件

3

我正在尝试通过Java 8中的编译时注释处理生成源代码的配置文件。

据我所知,在getSupportedAnnotationTypes类列出的每个注释中,处理器将被调用一次。

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new LinkedHashSet<>();
        set.add(MCPlugin.class.getCanonicalName());
        set.add(MCAPIVersion.class.getCanonicalName());
        set.add(MCAuthor.class.getCanonicalName());
        set.add(MCAPIVersion.class.getCanonicalName());
        set.add(MCDepend.class.getCanonicalName());
        set.add(MCLoad.class.getCanonicalName());
        set.add(MCLoadBefore.class.getCanonicalName());
        set.add(MCSoftDepend.class.getCanonicalName());
        set.add(MCCommand.class.getCanonicalName());

        return set;
    }

实际上,我不想使用一个注解处理器处理所有这些注解(这样做是正确的吗?),因为它会导致与MCCommand注解的问题。因此,我的计划是创建另一个注解处理器,仅处理MCCommand注解。

我的问题是,两个处理器的输出应该进入同一个输出文件。(这可能吗?)

我已经尝试过以这种方式重新打开资源文件(这也是我最初打开它的方式):

FileObject file = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "config.yml");

这会导致错误或覆盖现有文件。

TlDr:我如何让我的注解处理器编辑另一个注解处理器生成的文件?


Filer#getResource 这个方法有效吗? - undefined
不幸的是,它只会抛出一个FilerException异常,显示“尝试重新打开文件...” - undefined
2个回答

3
我知道这个内容有些老旧,但它可能会对其他人有所帮助。
你可以识别文件路径并像普通文件一样进行编辑(删除、截断、追加等)。
在此过程中,如果文件不存在,它将被创建。但是文件内容不会被删除。
    public Path createIdentifyResource(String file) throws IOException {
        try {
            FileObject fileObject = processingEnv.getFiler().getResource(StandardLocation.SOURCE_OUTPUT,
                    "", file);
            return new File(fileObject.toUri()).toPath();
        } catch (IOException e) {
            FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT,
                    "", file);
            return new File(fileObject.toUri()).toPath();
        }
    }

这个过程很简单。首先尝试获取资源,看它是否存在。如果失败了,就会尝试创建该资源。最后,获取URI并将其转换为路径。


2

经过多小时的查看FilerFileObject源代码后,我找到了一个解决方案/解决方法。

要访问JavacFiler,需要将其降级为Filer并添加com.sun.tools作为依赖项。

Filer向下转换为JavacFiler以访问更多方法。

Filer有一个createResource(...)getResource(...)方法,这两种方法似乎都是相同的,但区别在于createResource(...)仅打开FileObject进行写操作,而getResource(...)则仅进行读取操作。

因此,要修改另一个注释处理器的文件,需要执行以下操作:

  1. 只读方式打开文件
  2. 读取文件内容
  3. 关闭文件
  4. 以只写方式重新打开文件
  5. 将旧内容写入其中
  6. 添加更多数据
FileObject jfo = filer.getResource(StandardLocation.SOURCE_OUTPUT, "", "test.txt");
String msg = TUtils.JFOToString(jfo);    // Reads FileObject as String
jfo.delete();

jfo = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "test.txt");
TUtils.writeJFO(jfo, msg + "Hallo ich bin Processor 2");    // Writes String to FileObject
filer.close();

这感觉像是一个技巧,但似乎有效。

这意味着您的注解处理器在非JRE编译器中将无法工作,比如Eclipse的JDT。也许可以使用反射来测试类是否存在,然后再使用它,并查看是否需要进行类似的更改,以使JDT在这种情况下能够正常工作? - undefined
谢谢,我会在后续的开发中注意这一点。 目前我还在为两个处理器同时访问一个资源而苦恼。 - undefined
1
在Java 8中,Filer接口确实具有getcreate方法;为什么需要进行强制转换呢? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接