How to extract the value Class[] value()
in the annotation
package com.example;
public @interface ExampleAnnotation {
Class[] value();
}
Without the annotation begin in the runtime of the Annotation Processor.
How to extract the value Class[] value()
in the annotation
package com.example;
public @interface ExampleAnnotation {
Class[] value();
}
Without the annotation begin in the runtime of the Annotation Processor.
This is my best way. I use the java stream API for more simplicity.
Write this in your processor 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).
When you access a class parameter, a MirroredTypeException
is thrown, while when you access a class array parameter, a MirroredTypesException
is thrown. Both provide the TypeMirrors.
In the following example, the methods mirror
and mirrorAll
wrap the verbose try-catch pattern and provide the respective TypeMirrors
. They accept the respective getter via a method reference.
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();
}
}
I use the following utility i built for my own annotation processors: