如何使用@Target(ElementType.TYPE_USE)处理注释?

时间:2017-02-10 16:43:19

标签: java java-8 annotations annotation-processing annotation-processor

我正在实现一个注释处理器,以确保标注注释的元素是实现某个接口的类的实例,或者是实现某个接口的类型的使用:

@Documented
@Target(value = { ElementType.PARAMETER, ElementType.TYPE_USE })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface AuditSubject {

}

public interface Auditable {
    // methods that provide data for writing a log entry...
}

public class Report implements Auditable {

}

对于带注释的元素,必须在方法执行后(使用AOP)创建日志条目。示例:

@CreateLogEntry
public Result persist(@AuditSubject Report newReport) {
    // A log entry must be created based on the incoming 'newReport' instance.    
}

@CreateLogEntry
public UpdateResult<@AuditSubject Report> update(Report update) {
    // A log entry must be created based on the updated report, which is not the same instance as 'update' but an equivalent one.
} 

@CreateLogEntry
public Result persistBatch(List<@AuditSubject Report> batch) {
    // A log entry must be created for each element in 'batch' after this method's execution.
}

必须创建日志条目,前提是Report实现Auditable;如果没有,则抛出运行时异常( Yikes,我忘了实现接口!)。因此,注释处理器有助于在编译时捕获程序员的错误。到目前为止,我已经成功检查了参数的所有用途,但没有在类型用途中检查。注释处理器的相关代码如下:

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    for (Element annotated : roundEnv.getElementsAnnotatedWith(AuditSubject.class)) {
        // Only prints elements with ElementKind.PARAMETER)!
        this.messager.printMessage(Kind.NOTE, TextUtils.replaceParams("annotated: {} ; Kind : {} ; enclosing : {}", annotated,  annotated.getKind(), annotated.getEnclosingElement()));

        if (annotated.getKind() == ElementKind.PARAMETER) {
            // Code here works as expected, raises errors for annotated parameters of classes that don't implement Auditable.
        } else if (annotated.getKind() == ElementKind.WHAT_TO_USE) {
            // What ElementKind do I need to use here?
        }
    }

    return false;
}

只识别带有ElementKind.PARAMETER种类的带注释元素(process()循环中的第一行只为'newReport'打印一行。如何检查带注释的类型是否实现{{1 }}?没有“Auditable”常量可供使用。我无法找到有关此事的任何相关信息。谢谢你的关注。

2 个答案:

答案 0 :(得分:5)

Java注释处理API是在Java仅支持声明注释时设计的。 API仅支持访问声明,例如字段,方法和方法参数。它不访问局部变量声明,也不访问方法体内的其他注释,也不键入注释。

如果您希望在方法体中处理类型注释或注释,则需要编写自己的代码来递归类型或递归检查方法中的代码行。

另一种方法是使用像Checker Framework这样的工具。它实现了自己的访问者,因此在每次出现类型注释时都会调用构建在其上的注释处理器。

答案 1 :(得分:0)

为什么不使用TYPE_PARAMETER? javax.annotation.processing.Processor API文档有:

An annotation type is considered present if there is at least one annotation of that type present on an element enclosed within the root elements of a round. For this purpose, a type parameter is considered to be enclosed by its generic element. Annotations on type uses, as opposed to annotations on elements, are ignored when computing whether or not an annotation type is present.

javax.lang.model.element.TypeParameterElement
Element getGenericElement()
Returns the generic class, interface, method, or constructor that is parameterized by this type parameter.