【问题标题】:Find type parameter of method return type in Java 6 annotation processor在 Java 6 注解处理器中查找方法返回类型的类型参数
【发布时间】:2009-09-06 12:26:11
【问题描述】:

我正在编写一个工具,它使用注释处理器根据带注释的类的方法的返回类型生成源代码。返回类型始终是定义类型变量T 的接口A 的某个子类型(接口或类)。

interface A<T>{T m();};

我想找到方法m()返回值类型变量T的类型参数。

返回类型由注释处理器表示为javax.lang.model.type.TypeMirror 实例。最简单的情况是直接返回A&lt;T&gt;。

@SomeAnnotation
class SomeClass{
    A<T> x();
}

找出T 的处理器代码非常简单。 (为了保持代码简单,我将在这里转换而不是使用访问者 API。)

DeclaredType type = (DeclaredType) typeMirror;
TypeMirror t = type.getTypeArguments().get(0);

返回类型的TypeMirror 是javax.lang.model.type.DeclaredType,T 是第一个类型参数。结果t 是javax.lang.model.type.TypeVariable 对应T。这同样适用于具体的返回类型A&lt;B&gt;(B 是某种类型:interface B{})。 t 的结果是 DeclaredType 代表 B。

其他结果类型开始变得复杂:

interface Subtype<T> extends A<T>{}
interface Concrete extends A<B>{};
interface Multiple<B,T> extends A<T>{}
interface Bounds<T extends B> extends A<T>{}
interface Hierarchy extends Concrete{}
Subtype<B>          -> DeclaredType B
Subtype<T>          -> TypeVariable T
Concrete            -> DeclaredType B
Multiple<B,T>       -> TypeVariable T or DeclaredType B depeding on Multiple
Multiple<B,B>       -> TypeVariable B
<T extends B> A<T>  -> TypeVariable T with super class bound B
Bound<B>            -> DeclaredType B
Bound<C>            -> DeclaredType C (subtype of B)
Hierarchy           -> TypeVariable T

有没有办法为T 找到正确的类型参数而无需镜像整个java 类型系统?

【问题讨论】:

    标签: java generics annotations annotation-processing


    【解决方案1】:

    看看http://docs.oracle.com/javase/6/docs/api/javax/lang/model/util/Types.html#asMemberOf%28javax.lang.model.type.DeclaredType,%20javax.lang.model.element.Element%29

    我用它来解决这个问题,并在这个 pull request 中将解决方案贡献给了 WsDoc 项目:https://github.com/versly/wsdoc/pull/7

    我做了这样的事情:

          Type.MethodType methodType = (Type.MethodType) processingEnv.getTypeUtils().asMemberOf(declaredTypeThatExtendsSomeGenericParent, methodToGetReturnTypeForAsExecutableElement);
          TypeMirror type = methodType.getReturnType();
    

    【讨论】:

      【解决方案2】:
       public AnnotationProcessor getProcessorFor(
                  Set<AnnotationTypeDeclaration> atds,
                  AnnotationProcessorEnvironment env) {
              return new SomeAnnotationProcessor(env);
          }
      
          private static class SomeAnnotationProcessor implements AnnotationProcessor {
              private final AnnotationProcessorEnvironment env;
      
              SomeAnnotationProcessor(AnnotationProcessorEnvironment env) {
                  this.env = env;
              }
      
              public void process() {
                  for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) {
                      System.out.println("in class: " + typeDecl);
                      typeDecl.accept(getDeclarationScanner(
                              new SomeClassVisitor(), NO_OP));
                  }
              }
      
              private static class SomeClassVisitor extends SimpleDeclarationVisitor {
                  @Override
                  public void visitMethodDeclaration(
                          MethodDeclaration methodDeclaration) {
                      System.out.println("visiting method: "+methodDeclaration + " -> "+methodDeclaration.getReturnType());
                      methodDeclaration.getReturnType().accept(new SomeTypeVisitor());
                  }
              }
          }
      
          private static class SomeTypeVisitor implements TypeVisitor {
      
              public void visitClassType(ClassType classType) {           
                  System.out.println("classType: " + classType + " -> "+classType.getClass());                
              }
      
              @Override
              public void visitInterfaceType(InterfaceType interfaceType) {
                  Types types = annotationProcessorEnvironment.getTypeUtils();
                  TypeDeclaration typeDeclaration = annotationProcessorEnvironment
                          .getTypeDeclaration("A");           
                  Collection<InterfaceType> superinterfaces = interfaceType
                          .getSuperinterfaces();                      
                  System.out.println("interfaceType: " + interfaceType + " -> "
                          + superinterfaces);
                  DeclaredType typeOfA = types.getDeclaredType(typeDeclaration);
                  boolean isSubTypeOfA = types.isSubtype(interfaceType, typeOfA);         
                  if (isSubTypeOfA) {
                      findTypeVariable(types, superinterfaces, typeOfA);
                  }
                  Iterator<TypeMirror> iterator = interfaceType
                          .getActualTypeArguments().iterator();
                  while (iterator.hasNext()) {
                      TypeMirror next = iterator.next();
                      next.accept(new SomeTypeVisitor());
                  }
              }
      
              public void visitTypeVariable(TypeVariable typeVariable) {          
                  System.out.println("typeVariable: "
                          + typeVariable.getDeclaration() + " -> "+typeVariable.getClass());              
              }
      
              private void findTypeVariable(Types types,
                      Collection<InterfaceType> superinterfaces, DeclaredType typeOfA) {
                  for (InterfaceType superInterface : superinterfaces) {
                      TypeMirror erasure = types.getErasure(superInterface);
                      if (erasure.equals(typeOfA)) {
                          System.out.println("true, "+superInterface.getActualTypeArguments());
                      } else {
                          System.out.println("false: " + typeOfA + " =!= "
                                  + erasure);
                          findTypeVariable(types, superInterface.getSuperinterfaces(), typeOfA);
                      }
                  }
              }
      
      
          }
      

      【讨论】:

      • 这很简单。它将为@SomeAnnotation class Something{ Concrete x(){} } 返回 DeclaredType Concrete,并且接口 Concrete 扩展 A。正确的结果是 B。实现必须弄清楚 A 中类型变量 T 的类型参数是 B 表示混凝土。或者更简单地说,方法的方法返回值是 A 的子类型。问题是:对于给定的 A 子类型,A 中的类型参数 T 是什么。
      • 你的代码基本一样:DeclaredType type = (DeclaredType) typeMirror; TypeMirror t = type.getTypeArguments().get(0);从上面。访问者只能区分类型变量和声明类型。
      • 嗨,我更新了代码。顺便说一句,我得到了层次结构的 DeclaredType B,这似乎是正确的。
      【解决方案3】:

      这似乎是一个常见问题,所以对于那些来自 Google 的人来说:有希望。

      Dagger DI 项目在 Apache 2.0 许可下获得许可,并包含一些用于在注释处理器中处理类型的实用方法。

      特别是,Util 类可以在 GitHub (Util.java) 上完整查看,并定义了一个方法 public static String typeToString(TypeMirror type)。它使用 TypeVisitor 和一些递归调用来构建类型的字符串表示。这是一个sn-p供参考:

      public static void typeToString(final TypeMirror type, final StringBuilder result, final char innerClassSeparator)
      {
          type.accept(new SimpleTypeVisitor6<Void, Void>()
          {
              @Override
              public Void visitDeclared(DeclaredType declaredType, Void v)
              {
                  TypeElement typeElement = (TypeElement) declaredType.asElement();
      
                  rawTypeToString(result, typeElement, innerClassSeparator);
      
                  List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
                  if (!typeArguments.isEmpty())
                  {
                      result.append("<");
                      for (int i = 0; i < typeArguments.size(); i++)
                      {
                          if (i != 0)
                          {
                              result.append(", ");
                          }
      
                          // NOTE: Recursively resolve the types
                          typeToString(typeArguments.get(i), result, innerClassSeparator);
                      }
      
                      result.append(">");
                  }
      
                  return null;
              }
      
              @Override
              public Void visitPrimitive(PrimitiveType primitiveType, Void v) { ... }
      
              @Override
              public Void visitArray(ArrayType arrayType, Void v) { ... }
      
              @Override
              public Void visitTypeVariable(TypeVariable typeVariable, Void v) 
              {
                  result.append(typeVariable.asElement().getSimpleName());
                  return null;
              }
      
              @Override
              public Void visitError(ErrorType errorType, Void v) { ... }
      
              @Override
              protected Void defaultAction(TypeMirror typeMirror, Void v) { ... }
          }, null);
      }
      

      我正忙于我自己的生成类扩展的项目。 Dagger 方法适用于复杂情况,包括通用内部类。我有以下结果:

      我的带有要扩展字段的测试类:

      public class AnnotationTest
      {
          ...
      
          public static class A
          {
              @MyAnnotation
              private Set<B<Integer>> _bs;
          }
      
          public static class B<T>
          {
              private T _value;
          }
      }
      

      在处理器为_bs 字段提供的Element 上调用Dagger 方法:

      accessor.type = DaggerUtils.typeToString(element.asType());
      

      生成的源(当然是自定义的)。请注意令人敬畏的嵌套泛型类型。

      public java.util.Set<AnnotationTest.B<java.lang.Integer>> AnnotationTest.A.getBsGenerated()
      {
          return this._bs;
      }
      

      编辑:调整概念以提取第一个通用参数的 TypeMirror,否则为 null:

      public static TypeMirror getGenericType(final TypeMirror type)
      {
          final TypeMirror[] result = { null };
      
          type.accept(new SimpleTypeVisitor6<Void, Void>()
          {
              @Override
              public Void visitDeclared(DeclaredType declaredType, Void v)
              {
                  List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
                  if (!typeArguments.isEmpty())
                  {
                      result[0] = typeArguments.get(0);
                  }
                  return null;
              }
              @Override
              public Void visitPrimitive(PrimitiveType primitiveType, Void v)
              {
                  return null;
              }
              @Override
              public Void visitArray(ArrayType arrayType, Void v)
              {
                  return null;
              }
              @Override
              public Void visitTypeVariable(TypeVariable typeVariable, Void v)
              {
                  return null;
              }
              @Override
              public Void visitError(ErrorType errorType, Void v)
              {
                  return null;
              }
              @Override
              protected Void defaultAction(TypeMirror typeMirror, Void v)
              {
                  throw new UnsupportedOperationException();
              }
          }, null);
      
          return result[0];
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-24
        • 1970-01-01
        • 2020-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-16
        • 2023-01-11
        相关资源
        最近更新 更多