我有两个带有方法的类,我想将这两个类的方法组合到一个类中。
@Service("ITestService")
public interface ITest1
{
@Export
void method1();
}
@Service("ITestService")
public interface ITest2
{
@Export
void method2();
}
结果应该是:
public interface ITestService extends Remote
{
void method1();
void method2();
}
我的AnnotationProcessor的第一次运行会生成正确的输出(因为RoundEnvironment包含两个类)。
但是如果我编辑其中一个类(例如添加一个新方法),RoundEnviroment只包含已编辑的类,因此结果如下(将newMethod()添加到接口ITest1)
public interface ITestService extends Remote
{
void method1();
void newMethod();
}
现在缺少method2。我不知道如何解决我的问题。有没有办法(Enviroment),访问项目中的所有类?或者还有另一种解决方法吗?
生成类的代码很长,所以这里简要介绍我如何生成类。我使用env.getElementsAnnotatedWith(Service.class)
遍历Elements并提取方法并将它们写入新文件:
FileObject file = null;
file = filer.createSourceFile("com/test/" + serviceName);
file.openWriter().append(serviceContent).close();
答案 0 :(得分:8)
- 选项1 - 从命令行手动编译---
我试图做你想要的,这是从处理器访问所有类,并且正如人们评论的那样,javac总是编译所有类,并且从RoundEnvironment我可以访问所有正在编译的类,每次(甚至当没有文件改变时),只有一个小细节:只要所有类显示在要编译的类列表上。
我已经用两个接口做了一些测试,其中一个(A)依赖于(B)其他(扩展),我有以下场景:
Implicitly compiled files were not subject to annotation processing.
如果将编译器设置为详细,那么您将获得明确的消息,显示每轮中将处理哪些类。这是我明确传递接口(A)时得到的:
Round 1:
input files: {com.bearprogrammer.test.TestInterface}
annotations: [com.bearprogrammer.annotation.Service]
last round: false
这是我在添加两个课程时所得到的:
Round 1:
input files: {com.bearprogrammer.test.AnotherInterface, com.bearprogrammer.test.TestInterface}
annotations: [com.bearprogrammer.annotation.Service]
last round: false
在这两种情况下,我都看到编译器会解析这两个类,但顺序不同。对于第一种情况(仅添加一个接口):
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\TestInterface.java]]
[parsing completed 15ms]
[search path for source files: src\main\java]
[search path for class files: ...]
[loading ZipFileIndexFileObject[lib\processor.jar(com/bearprogrammer/annotation/Service.class)]]
[loading RegularFileObject[src\main\java\com\bearprogrammer\test\AnotherInterface.java]]
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\AnotherInterface.java]]
对于第二种情况(添加了所有接口):
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\AnotherInterface.java]]
...
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\TestInterface.java]]
[search path for source files: src\main\java]
[search path for class files: ...]
...
这里重要的细节是编译器在第一种情况下将依赖项作为编译的隐式对象加载。在第二种情况下,它将加载它作为待编译对象的一部分(您可以看到这一点,因为它在解析提供的类之后开始搜索文件的其他路径)。而且似乎隐式对象不包含在注释处理列表中。
有关编译过程的更多详细信息,请查看此Compilation Overview。没有明确说明要处理哪些文件。
在这种情况下,解决方案是始终将所有类添加到编译器的命令中。
---选项2 - 从Eclipse编译---
如果您是从Eclipse编译,增量构建将使您的处理器失败(尚未测试)。但我认为你可以绕过那个要求干净的构建(Project> Clean ...,也没有测试过它)或编写一个总是清理classes目录并设置Ant Builder from Eclipse的Ant构建
---选项3 - 使用构建工具---
如果您正在使用其他一些构建工具,如Ant,Maven或Gradle,最好的解决方案是将源代码生成在与编译不同的步骤中。您还需要在单独的上一步中编译处理器(如果在Maven / Gradle中使用多项目构建,则需要使用单独的子项目)。这将是最好的方案,因为:
-proc:only
选项仅处理文件)对于第三个选项,您还可以设置Ant构建脚本,以便从Eclipse生成这些文件,作为在Java构建器之前运行的构建器。在某个特殊文件夹中生成源文件,并将其添加到Eclipse中的classpath / buildpath。
答案 1 :(得分:3)
NetBeans @Messages注释为同一个包中的所有类生成单个 Bundle.java 文件。由于annotation processor中的以下技巧:
,它可以正确地进行增量编译Set<Element> toProcess = new HashSet<Element>();
for (Element e : roundEnv.getElementsAnnotatedWith(Messages.class)) {
PackageElement pkg = findPkg(e);
for (Element elem : pkg.getEnclosingElements()) {
if (elem.getAnnotation(Message.class) != null) {
toProcess.add(elem);
}
}
}
// now process all package elements in toProcess
// rather just those provided by the roundEnv
PackageElement findPkg(Element e) {
for (;;) {
if (e instanceof PackageElement) {
return (PackageElement)e;
}
e = e.getEnclosingElement();
}
}
通过执行此操作,即使仅在包中的单个源文件上调用了编译,也可以确保包中的所有(顶级)元素一起处理。
如果您知道在哪里查找注释(包中的顶级元素,甚至包中的任何元素),您应该能够始终获得所有此类元素的列表。