我有几个使用java注释处理器执行的检查,但我也想检查未注释的类型。
例如,如果我们假设我有一个类似@Responsible(name="xyz")
的注释,那么挂钩编译过程以强制所有顶级类型都有注释的最佳方法是什么。
使用我当前的实现,我依赖于两个注释,预期的一个(Responsible)和一个包级别。后者用于“开火”。即使没有预期的注释,注释处理器也是如此。 在解雇的注释处理器内,我然后搜索&过滤磁盘上的java文件(使用传递给编译器的参数)来收集我想要处理的所有文件,并在java文件对应于处理器正在处理的带注释类型时过滤它们。如果有人在未指定注释的情况下提交新文件,则构建失败。
是不是有一种更清洁的方式来查找未注释的'类型?
答案 0 :(得分:3)
您不必依赖注释来运行处理器。如the documentation中所述:
如果不存在注释类型,则仍会出现注释处理,但只有通用处理器支持处理" *"可以声明(空)一组注释类型。
你找到课程的方法有点笨拙。相反,您可以依赖包和类之间的父子关系:找出顶级包元素的名称,包含有趣的类,并使用{{1}下载到该包(和/或它的子包)中}。或者,您可以在该包中找到一个类 - 然后使用Element#getEnclosedElements
提升到最顶层的包。可以使用Elements#getPackageElement通过名称获取包对象,并且可以使用Elements#getTypeElement按名称获取类对象。
与手动交互文件和目录相比,不那么脆弱,如果源文件在目录之间移动或拆分,则不会中断。
请注意,包含顺序为Element#getEnclosingElement
,每个包的父级都是包本身,而不是它的父级"包"a single package" -> "class" -> "method" -> ...
中未包含net.example
。
答案 1 :(得分:2)
要处理所有元素,我错过了RoundEnvironment#getRootElements()
是我正在寻找的元素列表,如果声明处理器使用*
处理所有内容。
因此,为了检查所有类型是否都使用@Responsible
进行了注释,我最终得到了
@AutoService(Processor.class)
public class ResponsibleAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
List<ElementKind> typeKinds = Arrays.asList(ElementKind.ENUM, ElementKind.INTERFACE, ElementKind.CLASS);
// let's gather all types we are interrested in
Set<String> allElements = env.getRootElements()
.stream()
.filter(e -> typeKinds.contains(e.getKind())) // keep only interesting elements
.map(e -> e.asType().toString()) // get their full name
.collect(Collectors.toCollection(() -> new HashSet<>()));
Set<String> typesWithResponsible = new HashSet<>();
annotations.forEach(te -> {
if (Responsible.class.getName().equals(te.asType().toString())) {
// We collect elements with an already declared ownership
env.getElementsAnnotatedWith(te).forEach(e -> typesWithResponsible.add(e.asType().toString()));
}
});
allElements.removeAll(typesWithResponsible);
allElements.forEach(cname -> processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, cname + " must be annotated with @" + Responsible.class.getName() + " to declare a ownership"));
return false;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
// We want to process all elements
return Collections.singleton("*");
}
}