有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何从typeElement获取实际类型?

我正在编写自定义注释处理器。虽然我能够处理没有泛型类型的类类型,但无法获得泛型类型的实际类型

MyBase界面

interface MyBase<T, S> {
  void method1(S, T);
}

例1

public class KpA{
 ...
}

示例类2

public class KpB{
 ...
}

目标注释类

@MyAnnotation
interface MyHandler extends MyBase<KpA, KpB>{

}

处理代码段

    TypeElement[] getActualTypes(ProcessingEnvironment pEnv, TypeElement element){
        List<TypeElement> myBaseElement = element.getInterfaces().stream().map(v-> (TypeElement) pEnv.getTypeUtils().asElement(v)).collect(Collectors.toList());
        myBaseElement.get(0).getTypeParameters().stream().forEach(System.out::println);
         return null;
    }

当ISysout使用getTypeParameters时,我得到输出为S and T;我怎样才能得到KpA and KpB


共 (1) 个答案

  1. # 1 楼答案

    当你处理类型系统时,准确地理解你想要什么是很重要的。您想要这些类型参数,是因为它们的类型变量在基类型的某些字段/方法中使用吗?例如,您的参数化基类型类似于Collection<SomeItem>,您想知道add的返回类型吗?或者MyBase是某种像Clonable这样的标记接口,而你想要的是它的参数

    不管怎样;让我们假设,您的情况与问题中描述的完全一样:MyBase是某个接口,您只是出于未知的原因想要它的参数。这里有一个不灵活、愚蠢的方法来实现这一点:

    // instance of javax.lang.model.util.Types
    protected final Types types;
    
    // instance of javax.lang.model.util.Elements
    protected final Elements el;
    
    // TypeMirror for java.lang.Object
    protected final TypeMirror theObject = ...
    
    private static final TYPE_REFINER = new DeclaredTypeRefiner();
    
    private class DeclaredTypeRefiner extends TypeKindVisitor6<DeclaredType, TypeMirror> {
      @Override
      public DeclaredType visitDeclared(DeclaredType type, TypeMirror desirableParent) {
        if (types.isSameType(types.erasure(type), desirableParent)) {
          return type;
        }
    
        return null;
      }
    
      @Override
      public DeclaredType visitUnknown(TypeMirror typeMirror, TypeMirror typeMirror2) {
        return defaultAction(typeMirror, typeMirror2);
      }
    
      @Override
      protected DeclaredType defaultAction(TypeMirror type, TypeMirror desirableParent) {
        if (types.isSameType(type, theObject)) {
          return null;
        }
    
        final List<? extends TypeMirror> superTypes = types.directSupertypes(type);
    
        for (TypeMirror parent : superTypes) {
            final DeclaredType discovered = visit(parent, desirableParent);
    
          if (discovered != null) {
             return discovered;
          }
        }
    
        return null;
      }
    }
    
    public TypeMirror getTypeArg(TypeMirror actual, TypeMirror base, int idx) {
      DeclaredType found = TYPE_REFINER.visit(actual, types.erasure(base));
    
      return found.getTypeArguments().get(idx);
    }
    

    要获取第二个参数的类型(例如KpB):

    // type mirror of MyHandler goes here
    TypeMirror concrete = ...
    
    // your base type goes here. Real code should cache it
    TypeMirror base = types.getDeclaredType(el.getTypeElement("com.example.MyBase"));
    
    // boom
    TypeMirror arg = typeHelper.getTypeArg(concrete, base, 1);
    

    这里发生的事情如下:

    1. 在父类型上迭代,寻找DeclaredTypes(例如类和接口)
    2. 检查声明的类型是否是我们的基本接口
    3. 如果我们找到了它,将其返回给调用者,这样它就可以检查args类型

    诀窍在于对directSupertypes的调用:正如其文档中所解释的,该方法自动为您解析类型参数

    我们比较类型擦除(也称为原始类型),因为它们被期望以有意义的方式进行比较(这或多或少与比较类型元素相同)。请不要试图将泛型类型与isSameType进行比较——由于类型系统的工作方式,这肯定会产生令人惊讶的结果


    请注意,由于多重继承,上面的代码可能并不总是提供正确的结果:MyHandler可能从多个父级继承MyBase,从而导致对TS的真实身份的混淆。如果这些变量没有在任何地方使用(例如,我们谈论的是一个纯标记接口),它将仍然是一个谜:编译器不关心,所以没有人知道(我猜,您不想手动计算上/下限,是吗?)如果在某些方法/字段中使用了这些变量,那么您应该能够通过在MyHandler上检查这些方法/字段来获取它们的类型(如何做到这一点是一个稍微棘手的问题,值得再问一个问题)