选择具有给定注释的类

时间:2016-02-22 14:39:32

标签: java ant annotations

我有一堆java类的源文件。我想找到那些由给定的注释类注释的类。应将这些类的名称写入服务提供者列表文件。

我可以使用任何机器来帮助我完成这项任务吗?或者我是否必须从头开始自己实施?

如果我必须自己做,我可以想到几种方法。

  1. 用Java编写Ant任务。让它使用合适的(可能是可配置的)类路径创建ClassLoader。使用该加载器(尝试)加载与输入文件匹配的类,以便检查它们的注释。需要在运行时保留注释,并完全初始化所有涉及的类及其依赖项。

  2. 使用javap检查类。由于我不知道javap的编程接口(你呢?),这可能意味着迭代文件并为每个文件运行一个新进程,然后以合适的方式按摩创建的输出。也许可以使用<scriptdef> - ed任务。这适用于类文件注释保留,不需要初始化。

  3. 使用注释处理器在编译时收集信息。这应该能够使用仅源代码保留。但我没有编写或使用注释编译器的经验,因此我不确定这是否有效,并且需要进行大量研究才能找出一些细节。特别是如何激活ant使用的任务(Java 6 annotation processing configuration with Ant给出一些指示,就像What is the default annotation processors discovery process?)以及何时创建输出文件(在每一轮中,或仅在最后一轮中)

  4. 您认为哪一项成功的机会最大?你能为其中一个建议代码样本,这可能接近我想要的,我可以适当调整吗?

1 个答案:

答案 0 :(得分:0)

受到托马斯评论的鼓励,我尝试了方法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();
    }

}

到目前为止,我已使用https://stackoverflow.com/a/3644624/1468366中的<compilerarg> s将其与蚂蚁联系起来。我会尝试更好的东西,如果我成功将编辑此帖子以包含一些蚂蚁片段。