我有一堆 java 类的源文件。我想找到那些由给定注释类注释的类。这些类的名称应写入服务提供者列表文件。
有什么机器可以帮助我完成这项任务吗?或者我必须自己从头开始实现这个?
如果我必须自己做这件事,我可以想到几种方法。
用 Java 编写 Ant 任务。让它创建一个
ClassLoader
使用合适的(可能是可配置的)类路径。使用该加载器(尝试)加载与输入文件匹配的类,以便检查它们的注释。需要在运行时保留注释,并完全初始化所有涉及的类及其依赖项。使用 javap 检查类。因为我不知道
javap
的编程接口(interface)(你是吗?),这可能意味着迭代文件并为每个文件运行一个新进程,然后以合适的方式调整创建的输出。也许是<scriptdef>
-ed 任务可以用于此目的。这将与类文件注释保留一起使用,并且不需要初始化。使用注释处理器在编译时收集信息。这应该能够与仅保留源代码一起使用。但我没有编写或使用注释编译器的经验,所以我不确定这是否有效,并且需要大量研究来弄清楚一些细节。特别是如何激活任务以供 ant 使用( Java 6 annotation processing configuration with Ant 对此提供了一些指示, What is the default annotation processors discovery process? 也是如此)以及何时创建输出文件(在每一轮中,或仅在最后一轮中)。
您认为其中哪一个最有可能成功?您能否建议其中之一的代码示例,它可能接近我想要的并且我可以适当调整?
最佳答案
在 Thomas 评论的鼓励下,我尝试了方法 3,并让以下注释处理器工作得相当好:
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.tools.StandardLocation;
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class AnnotationServiceProcessor extends AbstractProcessor {
// Map name of the annotation to name of the corresponding service interface
private static Map<String, String> annotationToServiceMap = new HashMap<>();
static {
// Adapt this to your use, or make it configurable somehow
annotationToServiceMap.put("Annotation1", "Service1");
annotationToServiceMap.put("Annotation2", "Service2");
}
@Override public Set<String> getSupportedAnnotationTypes() {
return annotationToServiceMap.keySet();
}
// Map name of the annotation to list of names
// of the classes which carry that annotation
private Map<String, List<String>> classLists;
@Override public void init(ProcessingEnvironment env) {
super.init(env);
classLists = new HashMap<>();
for (String ann: getSupportedAnnotationTypes())
classLists.put(ann, new ArrayList<String>());
}
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment env) {
for (TypeElement ann: annotations) {
List<String> classes =
classLists.get(ann.getQualifiedName().toString());
for (Element elt: env.getElementsAnnotatedWith(ann)) {
QualifiedNameable qn = (QualifiedNameable)elt;
classes.add(qn.getQualifiedName().toString());
}
}
if (env.processingOver()) { // Only write results at the end
for (String ann: getSupportedAnnotationTypes()) {
try {
write(ann, classLists.get(ann));
} catch (IOException e) {
throw new RuntimeException(e); // UGLY!
}
}
}
return true;
}
// Write the service file for each annotation we found
private void write(String ann, List<String> classes) throws IOException {
if (classes.isEmpty())
return;
String service = annotationToServiceMap.get(ann);
Writer w = processingEnv.getFiler()
.createResource(StandardLocation.CLASS_OUTPUT,
"", "META-INF/services/" + service)
.openWriter();
classes.sort(null); // Make the processing order irrelevant
for (String cls: classes) {
w.write(cls);
w.write('\n');
}
w.close();
}
}
到目前为止,我已经使用 <compilerarg>
将其连接到 ant来自https://stackoverflow.com/a/3644624/1468366 。我会尝试更好的方法,如果成功,我将编辑这篇文章以包含一些 Ant 片段。
关于java - 选择具有给定注释的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35556410/