问题描述
我正在创建AnnotationProcessor,并且需要检查带注释的类型是否是指定类的子类型。 注释:
public @interface Component {
Class<?> supertype();
}
示例:(正确)
@Component(supertype = MyInterface.class)
public class MyClass implements MyInterface {
// ...
}
示例:(不正确,由于MyClass
不是String
的子类型,因此不能编译)
@Component(supertype = String.class)
public class MyClass implements MyInterface {
}
我知道我无法获得带注释的Class
,因为它尚未编译。
解决方法
您没有在问题中提及它,但我认为您遇到了TypeMirror
个问题。
这是一个非常老旧的解决方案,可用于进入TypeMirror
字段的supertype
,并将其与类型的基类进行比较:
@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;
}
如果我是您,那么我会进一步研究一下这些天是否有更好的选择,但是如果没有,这将解决您的问题。
,此版本不依赖于异常,它使用Element.getAnnotationMirrors
,该类型可能在其中使用。但是,它更加冗长:
@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;
}
,
使用以下代码获取注释中类值的TypeMirror
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();
}
然后使用此代码检查它是否是特定类的超类型
/**
* 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()));
}