如何访问方法参数的泛型类型参数上的注释?

How to access an annotation on a generic type parameter of a method argument?

假设我想使用反射检查以下 class:

class Foo {
   void bar(List<@Important String> b) {}
}

请注意,@Important 注释在参数本身上是 而不是 (然后我可以使用 Method.getParameterAnnotations()),但在它的类型参数上(这是当注释被声明为 ElementType.TYPE_USE).

时允许

有没有办法在 Java 11 中读取此类注释?

TL;DR — 请参阅此答案 discussing the subtle differences type parameters, type variables and type arguments.


long-winded版本

…Note that the @Important annotation is…on its type parameter

在你的Foo声明中…

class Foo {
   void bar(List<@Important String> b) {}
}

String 不是 type parameter. Nor is it a type variable. In your snippet there String is a type argument.

虽然我在 saying originally that ReferenceType type arguments can't have annotations (turns out they can 上得到纠正)我会把这些 JLS 作品留在这里让我保持谦虚 …

4.5.1. Type Arguments of Parameterized Types

Type arguments may be either reference types or wildcards. Wildcards are useful in situations where only partial knowledge about the type parameter is required.

TypeArguments:
   < TypeArgumentList >

TypeArgumentList:
   TypeArgument {, TypeArgument}

TypeArgument:
   ReferenceType
   Wildcard

Wildcard:
   {Annotation} ? [WildcardBounds]

WildcardBounds:
   extends ReferenceType
   super ReferenceType

为了完整性,类型参数

的JLS生产

4.4. Type Variables

A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.

A type variable is introduced by the declaration of a type parameter of a generic class, interface, method, or constructor…

TypeParameter:
   {TypeParameterModifier} TypeIdentifier [TypeBound]:

TypeParameterModifier:
   Annotation

尽管我从未在野外见过它们 — 直到今天 — 前面的 JLS 产品证实了带注释的 String type argument 在你的片段中确实是合法的 Java。每天学点新东西!

不幸的是,反射的这一部分 API 太可怕了。基本类型没有必要的查询方法,也没有 Visitor API 之类的东西。因此,任何试图进行全面内省的代码都别无选择,只能执行大量 instanceof 检查,以处理所有可能的情况。

如果你事先知道方法的类型应该是参数化类型,而你只想检查它的第一个类型参数的注释,你可以做得更简单一点,忽略所有其他可能的情况:

import java.lang.annotation.*;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.Method;
import java.util.*;

public class Main {
    public static void main(String[] args) throws NoSuchMethodException {
        Method m = Foo.class.getDeclaredMethod("bar", List.class);

        var at  = m.getAnnotatedParameterTypes()[0];
        var ata = ((AnnotatedParameterizedType)at).getAnnotatedActualTypeArguments()[0];

        // get all annotations
        for(var a: ata.getAnnotations()) {
            System.out.println(a);
        }

        // or check the presence of a known annotation
        System.out.println(ata.getAnnotation(Important.class) != null);
    }

    class Foo {
        void bar(List<@Important String> b) {}
    }
}

Demo on Ideone

@Important()
true