简体   繁体   English

Java 注释处理器:如何从注释中提取 class 值

[英]Java Annotation Processor: how to extract class values from an annotation

How to extract the value Class[] value() in the annotation如何提取注解中的值Class[] value()

package com.example;

public @interface ExampleAnnotation {
    Class[] value();
}

Without the annotation begin in the runtime of the Annotation Processor.如果没有注释,则在注释处理器的运行时开始。

I use the following utility i built for my own annotation processors:我使用为我自己的注释处理器构建的以下实用程序:

public List<TypeMirror> getClassArrayValueFromAnnotation(Element element, Class<? extends Annotation> annotation, String paramName) {
    Elements elements = this.processingEnv.getElementUtils();
    Types types = this.processingEnv.getTypeUtils();

    List<TypeMirror> values = new ArrayList<>();

    for (AnnotationMirror am : element.getAnnotationMirrors()) {
        if (types.isSameType(am.getAnnotationType(), elements.getTypeElement(annotation.getCanonicalName()).asType())) {
            for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : am.getElementValues().entrySet()) {
                if (paramName.equals(entry.getKey().getSimpleName().toString())) {
                    List<AnnotationValue> classesTypes = (List<AnnotationValue>) entry.getValue().getValue();
                    Iterator<? extends AnnotationValue> iterator = classesTypes.iterator();

                    while (iterator.hasNext()) {
                        AnnotationValue next = iterator.next();
                        values.add((TypeMirror) next.getValue());
                    }
                }
            }
        }
    }
    return values;
}

This is my best way.这是我最好的方法。 I use the java stream API for more simplicity.为了更简单,我使用 java stream API。

Write this in your processor class:在你的处理器 class 中写下这个:

    public static final String TARGET = "com.example.ExampleAnnotation";

    @Override
    public boolean process(Set<? extends TypeElement> types, RoundEnvironment environment) {
        //process once!
        if (!environment.processingOver())
            //For us to not depend on a class in this runtime
            //try to find the TypeElement of it
            types.stream()
                    .filter(type -> type.getQualifiedName().contentEquals(TARGET))
                    .findAny()
                    .ifPresent(type ->
                            //it exists!
                            //let us see elements annotated with it!
                            environment.getElementsAnnotatedWith(type)
                                    .forEach(element ->
                                            //got an element!
                                            //let us iterate over the annotation mirrors it has got
                                            //then search for the annotation with the targeted type
                                            element.getAnnotationMirrors()
                                                    .stream()
                                                    .filter(annotation -> this.processingEnv.getTypeUtils().isSameType(type.asType(), annotation.getAnnotationType()))
                                                    .findAny()
                                                    .ifPresent(annotation -> {
                                                        //bingo!
                                                        //lets get its values
                                                        Map<? extends ExecutableElement, ? extends AnnotationValue> values = annotation.getElementValues();

                                                        //lets find the annotation value `Class[] value()`
                                                        //any inappropriate value will be simply IGNORED (do not die strategy)
                                                        //this block trusts the javax documentation only!
                                                        //see javax.lang.model.element.AnnotationValue
                                                        List<TypeMirror> value = values.entrySet()
                                                                .stream()
                                                                .filter(entry -> entry.getKey().getSimpleName().contentEquals("value"))
                                                                .findAny()
                                                                .map(entry -> entry.getValue().getValue())
                                                                .filter(List.class::isInstance)
                                                                .<List<AnnotationValue>>map(List.class::cast)
                                                                .map(list ->
                                                                        list.stream()
                                                                                .map(AnnotationValue::getValue)
                                                                                .filter(TypeMirror.class::isInstance)
                                                                                .map(TypeMirror.class::cast)
                                                                                .collect(Collectors.toList())
                                                                )
                                                                .orElseGet(Collections::emptyList);

                                                        //Operate below ---------------------------------
                                                        //Operate above --------------------------------
                                                    })
                                    )
                    );

        return false;
    }

In many cases, you can get the TypeMirror from the exception that is thrown when you try to access a Class or Class[] parameter (see this answer).在许多情况下,您可以从尝试访问ClassClass[]参数时抛出的异常中获取TypeMirror (请参阅答案)。

When you access a class parameter, a MirroredTypeException is thrown, while when you access a class array parameter, a MirroredTypesException is thrown.访问 class 参数时,会抛出MirroredTypeException ,而访问 class 数组参数时,会抛出MirroredTypesException Both provide the TypeMirrors.两者都提供 TypeMirrors。

In the following example, the methods mirror and mirrorAll wrap the verbose try-catch pattern and provide the respective TypeMirrors .在以下示例中,方法mirrormirrorAll包装了详细的 try-catch 模式并提供各自的TypeMirrors They accept the respective getter via a method reference.它们通过方法引用接受各自的 getter。

public @interface ExampleAnnotation {
    Class<?> type();
    Class<?>[] types();
}

private void process(TypeElement typeElement){
    ExampleAnnotation annotation = typeElement.getAnnotation(ExampleAnnotation.class);
    TypeMirror type = mirror(annotation::type);
    List<? extends TypeMirror> types = mirrorAll(annotation::types);
}

public static TypeMirror mirror(Supplier<Class<?>> classValue) {
    try {
        var ignored = classValue.get();
        throw new IllegalStateException("Expected a MirroredTypeException to be thrown but got " + ignored);
    } catch (MirroredTypeException e) {
        return e.getTypeMirror();
    }
}

public static List<? extends TypeMirror> mirrorAll(Supplier<Class<?>[]> classValues) {
    try {
        var ignored = classValues.get();
        throw new IllegalStateException("Expected a MirroredTypesException to be thrown but got " + ignored);
    } catch (MirroredTypesException e) {
        return e.getTypeMirrors();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM