问题描述
@MyAnnotation
class Foo {
var bar: List<String> = emptyList()
}
class AnnotationProcessor : AbstractProcessor() {
override fun getSupportedAnnotationTypes(): MutableSet<String> = mutableSetof(...)
@KotlinPoetMetadataPreview
override fun process(annotations: MutableSet<out TypeElement>?,roundEnv: RoundEnvironment?
): Boolean {
val barPropType: TypeMirror = (roundEnv!!.getElementsAnnotatedWith(Command::class.java) as TypeElement)
.kotlinProperties
.first()
.type
return true
}
}
我现在想验证属性的类型是否可以从 List<String>
我能找到的一个解决方案是使用 TypeUtils
中可用的 isAssignable 方法,但为了做到这一点,我需要一个用于 List 的 TypeMirror 实例,但我无法做到想办法去做。我可以获取 List 的实例并执行擦除以获取原始类型的 TypeMirror
,但这对我没有帮助,因为它可以分配给任何 List<>
,例如 List<Integer>
:
val listType = processingEnv.elementUtils.getTypeElement(List::class.java.name).asType()
println((listType as DeclaredType).typeArguments) // E
println(processingEnv.typeUtils.isAssignable(barPropType,listType)) // false
println(processingEnv.typeUtils.isAssignable( // true,but also true when barPropType is List<Integer>
processingEnv.typeUtils.erasure(barPropType),listType,))
/**
* Get the type parameter for a {@link Collection}.
* @param type a parameterized collection type
* @return the type of elements in the collection
*/
private DeclaredType getCollectionType(TypeMirror type) {
if (type != null && typeUtils().isAssignable(type,collectionType.type)) {
// This is a bit of a hack; to work properly,we should walk up the inheritance hierarchy,tracking type
// parameters as we go. For example,if the type in question is StringList,which implements List<String>,// then this code would not work.
List<? extends TypeMirror> typeArguments = ((DeclaredType) type).getTypeArguments();
return (DeclaredType) typeArguments.get(0);
}
return null;
}
对于我的项目,我需要“适当”的解决方案,但我不知道如何实施。我做过这样的事情:
fun TypeElement.allSuperInterfaces(env: ProcessingEnvironment): List<TypeMirror> {
val result: MutableList<TypeMirror> = mutablelistof(this.asType())
result.addAll(interfaces)
var tocheckFurther = interfaces
while(tocheckFurther.isNotEmpty()) {
tocheckFurther = tocheckFurther
.mapNotNull { env.typeUtils.asElement(it) as? TypeElement }
.flatMap { it.interfaces }
.toMutableList()
result.addAll(tocheckFurther)
}
return result;
}
问题在于,在从 TypeMirror
到 TypeElement
的转换过程中,有关实际类型参数的信息丢失了:
((barPropType as DeclaredType).asElement() as TypeElement)
.allSuperInterfaces(processingEnv)
.forEach(::println)
输出:
java.util.List<E>
java.util.Collection<E>
java.lang.Iterable<E>
但与此同时,似乎需要进行这种转换,因为无法从 TypeMirror 获取已实现的接口(至少我知道)。
解决方法
您需要覆盖 AbstractProcessor init-Method。在那里你会得到“processingEnv”参数,你可以用它来为 List-class 初始化 TypeMirror, 您可以稍后与 isAssignable 一起使用。
在java中它看起来像这样:
public final class MyProcessor extends AbstractProcessor {
private TypeMirror listTM;
@Override public void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
listTM = processingEnv.getElementUtils().getTypeElement(List.class.getName()).asType();
}
}