I'm creating an AnnotationProcessor and I need to check if the annotated type is a subtype of an specified class. The annotation:
public @interface Component {
Class<?> supertype();
}
Example: (correct)
@Component(supertype = MyInterface.class)
public class MyClass implements MyInterface {
// ...
}
Example: (incorrect, this must not compile because MyClass
isn't a subtype of String
)
@Component(supertype = String.class)
public class MyClass implements MyInterface {
}
I know that I cannot get the annotated Class
because it isn't compiled yet.
You don't mention it in your question, but I assume you're running into TypeMirror
issues.
Here's a very old and hacky solution to get to the TypeMirror
of your supertype
field, and compare it against the type's base class:
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
for (Element element : roundEnvironment.getElementsAnnotatedWith(Component.class)) {
// TODO: Ensure element is a class before continuing
TypeElement typeElement = (TypeElement) element;
Component componentAnnotation = typeElement.getAnnotation(Component.class);
TypeMirror superType = null;
try {
// Hack to quickly get to TypeMirror of the annotation property
componentAnnotation.supertype();
} catch (MirroredTypeException mte) {
superType = mte.getTypeMirror();
}
// TODO: superType null check
Set<TypeMirror> validTypes = Sets.newHashSet(typeElement.getInterfaces());
validTypes.add(typeElement.getSuperclass());
if (!validTypes.contains(superType)) {
// TODO: throw something better
throw new IllegalArgumentException(typeElement.toString() + " does not implement or inherit from "
+ superType.toString() + " declared in @Component annotation");
}
}
return true;
}
If I were you I'd look into this a bit more to see if there are better options these days, but if not this will solve your problem.
This version does not rely on exceptions, it uses Element.getAnnotationMirrors
which is probably there for this type of use. It's a lot more verbose though:
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
for (Element element : roundEnvironment.getElementsAnnotatedWith(Component.class)) {
// TODO: Ensure element is a class before continuing
TypeMirror superType = null;
boolean found = false;
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
TypeElement annotationElement = (TypeElement) mirror.getAnnotationType().asElement();
if (annotationElement.getQualifiedName().contentEquals(Component.class.getName())) {
found = true;
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> kv :
mirror.getElementValues().entrySet()) {
ExecutableElement member = kv.getKey();
if (member.getKind() == ElementKind.METHOD &&
member.getSimpleName().contentEquals("supertype")) {
superType = (TypeMirror) kv.getValue().getValue();
break;
}
}
}
if (found) {
break;
}
}
// TODO: superType null check
TypeElement typeElement = (TypeElement) element;
Set<TypeMirror> validTypes = Sets.newHashSet(typeElement.getInterfaces());
validTypes.add(typeElement.getSuperclass());
if (!validTypes.contains(superType)) {
// TODO: throw something better
throw new IllegalArgumentException(typeElement.toString() + " does not implement or inherit from "
+ superType.toString() + " declared in @Component annotation");
}
}
return true;
}
Use the following code to get the TypeMirror of the class value in the annotation
public Optional<TypeMirror> getClassValueFromAnnotation(Element element, Class<? extends Annotation> annotation, String paramName) {
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())) {
AnnotationValue annotationValue = entry.getValue();
return Optional.of((DeclaredType) annotationValue.getValue());
}
}
}
}
return Optional.empty();
}
then use this code to check if it is a super type of a specific class
/**
* A wrapper over {@link Types#isAssignable(TypeMirror, TypeMirror)} which will apply type erasure on the targetClass before calling the wrapped method.
*
* @param typeMirror a {@link javax.lang.model.type.TypeMirror} object.
* @param targetClass a {@link java.lang.Class} object.
* @return a boolean.
*/
public boolean isAssignableFrom(TypeMirror typeMirror, Class<?> targetClass) {
return types.isAssignable(typeMirror, types.erasure(elements.getTypeElement(targetClass.getCanonicalName()).asType()));
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.