【问题标题】:How to get a List type with type arguments in Java annotation processor如何在 Java 注释处理器中获取带有类型参数的 List 类型
【发布时间】:2021-04-01 20:55:23
【问题描述】:

假设我有一个财产

@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&lt;String&gt; 分配

我能够找到的解决方案是使用TypeUtils 中可用的isAssignable 方法,但为了做到这一点,我需要一个TypeMirror for List 实例,但我无法找到一种方法做。我可以获得一个 List 实例并执行擦除以获得原始类型的 TypeMirror,但这对我没有帮助,因为它可以分配给任何 List&lt;&gt;,例如 List&lt;Integer&gt;

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,
        ))


This talk提出以下解决方案:

  /**
   * 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;
  }

full code

对于我的项目,我需要那个“合适的”解决方案,但我不知道如何实施。我做过这样的事情:

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;
}

这样做的问题是,在从TypeMirrorTypeElement 的转换过程中,有关实际类型参数的信息会丢失:

((barPropType as DeclaredType).asElement() as TypeElement)
            .allSuperInterfaces(processingEnv)
            .forEach(::println)

输出:

java.util.List<E>
java.util.Collection<E>
java.lang.Iterable<E>

但与此同时,似乎需要进行这种转换,因为无法从 TypeMirror 获取已实现的接口(至少我知道)。

实现这个涉及继承层次结构的解决方案的正确方法是什么?

【问题讨论】:

  • 所以你有一个带有特定注释@MyAnnotation 的类,你想编写一个处理器来做什么?该类中的所有变量都可以分配给List&lt;String&gt;?对不起,但我很困惑(主要是因为我对 kotlin 知之甚少)
  • 我只是想验证一下List&lt;&gt;的具体类型,例如List,某个TypeMirror。这种类型的镜像在上面的示例中表示为barPropType

标签: java kotlin javac annotation-processing


【解决方案1】:

您需要覆盖 AbstractProcessor init-Method。在那里你会得到“processingEnv”参数,你可以用它来为 List 类初始化 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();
    }
}

【讨论】:

  • 引用我的问题:“我能够找到的解决方案是使用 TypeUtils 中可用的 isAssignable 方法,但为了做到这一点,我需要一个用于 List 的 TypeMirror 实例,而我不是能够找到一种方法。我可以获取 List 的实例并执行擦除以获得原始类型的 TypeMirror,但这对我没有帮助,因为它可以分配给任何 List,例如 List :"。请具体说明如何使用isAssignable 来确定字段的通用类型。
  • Types.getTypeElement(Listclass.getName()) 不会那样做吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-14
  • 1970-01-01
  • 2017-01-05
  • 1970-01-01
  • 2013-08-04
相关资源
最近更新 更多