注解处理器无法获取类型变量的@Nullable注解问题排查与解决
问题描述
给定如下Java方法:
public static <T, @Nullable R> void foo(@Nullable Object obj, T t, @Nullable List<? extends @Nullable R> r)
通过Gradle配置的annotationProcessor可以读取@Nullable Object obj中的@Nullable注解,但无法读取类型变量R(包括<T, @Nullable R>和List<? extends @Nullable R>中的R)的@Nullable注解。
相关注解处理器代码片段如下:
List<? extends TypeParameterElement> typeParameterElements = element.getTypeParameters(); if (typeParameterElements != null && !typeParameterElements.isEmpty()) { methodInfo.setTypeParams(typeParameterElements.stream().map(it -> buildTypeName(it.asType())).collect(Collectors.toList())); } private String buildTypeName(TypeMirror typeMirror) { String annotations = ""; // 这里无法获取类型变量R的@Nullable注解! List<? extends AnnotationMirror> annotationMirrors = typeMirror.getAnnotationMirrors(); if (!annotationMirrors.isEmpty()) { annotations = annotationMirrors.stream().map(i -> i.toString() + " ").collect(Collectors.joining()); } if (typeMirror instanceof DeclaredType) { DeclaredType declaredType = (DeclaredType) typeMirror; List<? extends TypeMirror> args = declaredType.getTypeArguments(); if (args.isEmpty()) { return annotations + declaredType.asElement().toString(); } String argsNames = args.stream().map(this::buildTypeName).collect(Collectors.joining(", ")); return annotations + declaredType.asElement().toString() + "<" + argsNames + ">"; } // 永远不会走到WildcardType分支,为什么? if (typeMirror instanceof WildcardType) { WildcardType wildcardType = (WildcardType) typeMirror; TypeMirror up = wildcardType.getSuperBound(); if (up != null) { return "? super " + buildTypeName(up); } TypeMirror sp = wildcardType.getExtendsBound(); if (sp != null) { return "? extends " + buildTypeName(sp); } } if (typeMirror instanceof IntersectionType) { IntersectionType intersectionType = (IntersectionType) typeMirror; List<? extends TypeMirror> bounds = intersectionType.getBounds(); String boundNames = bounds.stream().map(this::buildTypeName).collect(Collectors.joining(" & ")); return annotations + typeUtils.asElement(intersectionType) + " extends " + boundNames; } if (typeMirror instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) typeMirror; TypeMirror lower = typeVariable.getLowerBound(); if (lower != null && !(lower instanceof NullType)) { return annotations + typeMirror + " super " + buildTypeName(lower); } TypeMirror upper = typeVariable.getUpperBound(); if (upper != null && !(upper instanceof NullType) && !Objects.equals("java.lang.Object", upper.toString())) { return annotations + typeMirror + " extends " + buildTypeName(upper); } } return annotations + typeMirror; }
问题原因
- 类型变量注解的读取位置错误:类型变量(比如
<T, @Nullable R>中的R)的@Nullable注解是附着在TypeParameterElement实例上的,而不是它对应的TypeMirror上。当前代码通过it.asType()将TypeParameterElement转为TypeMirror后调用getAnnotationMirrors(),自然无法获取到注解。 - 通配符边界的注解处理缺失:对于
List<? extends @Nullable R>中的通配符类型,虽然代码里有WildcardType分支,但当前逻辑没有正确处理通配符边界上的注解;另外,如果通配符边界是类型变量,也需要确保能读取到该变量本身的注解。
解决方案
1. 修正类型变量注解的读取逻辑
直接从TypeParameterElement获取注解,再结合其TypeMirror的信息构建类型名称:
List<? extends TypeParameterElement> typeParameterElements = element.getTypeParameters(); if (typeParameterElements != null && !typeParameterElements.isEmpty()) { methodInfo.setTypeParams(typeParameterElements.stream() .map(this::buildTypeParamName) // 改用专门处理TypeParameterElement的方法 .collect(Collectors.toList())); } // 新增处理TypeParameterElement的方法 private String buildTypeParamName(TypeParameterElement paramElement) { // 直接从TypeParameterElement获取注解 String annotations = paramElement.getAnnotationMirrors().stream() .map(AnnotationMirror::toString) .collect(Collectors.joining(" ")); // 结合TypeMirror的边界信息构建完整名称 return annotations + buildTypeName(paramElement.asType()); }
2. 完善通配符类型的处理逻辑
确保WildcardType分支能正确触发,并递归处理边界类型的注解:
if (typeMirror instanceof WildcardType) { WildcardType wildcardType = (WildcardType) typeMirror; TypeMirror superBound = wildcardType.getSuperBound(); if (superBound != null) { return "? super " + buildTypeName(superBound); } TypeMirror extendsBound = wildcardType.getExtendsBound(); if (extendsBound != null) { // 递归处理边界类型,自动继承类型变量的注解逻辑 return "? extends " + buildTypeName(extendsBound); } // 处理无边界的通配符 return "?"; }
3. 优化TypeVariable分支的返回逻辑
确保类型变量在无边界时,能正确返回带注解的名称:
if (typeMirror instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) typeMirror; TypeMirror lowerBound = typeVariable.getLowerBound(); if (lowerBound != null && !(lowerBound instanceof NullType)) { return annotations + typeVariable + " super " + buildTypeName(lowerBound); } TypeMirror upperBound = typeVariable.getUpperBound(); if (upperBound != null && !(upperBound instanceof NullType) && !Objects.equals("java.lang.Object", upperBound.toString())) { return annotations + typeVariable + " extends " + buildTypeName(upperBound); } // 无边界时直接返回带注解的类型变量名 return annotations + typeVariable; }
内容的提问来源于stack exchange,提问作者FredSuvn
相关产品推荐
相关产品推荐

