让我们有一个类型java.util.Map
:
public interface IdentifiableMap<ID, KEY, VALUE> extends Map<KEY, VALUE>{
ID getId();
}
还要有一个该类型的字段,它在其中一个类型参数上声明一个注释(从Java 8开始就是这样):
private IdentifiableMap<String, @Size(min=1) String, Integer> myMap = ...;
使用Java反射API,如何从此声明中找出为Map
接口的类型参数指定了哪些注释?换句话说,我想扣除已为@Size
的{{1}}类型参数提供了K
注释。
我知道如何从字段的java.util.Map
获取类型参数的注释,但我不知道如何将其与超类型AnnotatedParameterizedType
的类型参数相关联。
答案 0 :(得分:1)
不幸的是,这远非易事。以下代码假定您要查找直接实现或扩展类型的类型的注释,否则代码将变得更加复杂或者为间接实现多次的接口带来歧义问题。 / p>
static Annotation[][] getActualAnnotations(AnnotatedType at, Class<?> target) {
Type[] typeParameters = target.getTypeParameters();
if(typeParameters.length==0) return new Annotation[0][];
Type t=at.getType();
Map<Type,Annotation[]> atArgAnnos;
Class<?> raw;
if(t instanceof Class) {
atArgAnnos=Collections.emptyMap();
raw=(Class<?>)t;
if(raw==target) return new Annotation[typeParameters.length][0];
}
else if(t instanceof ParameterizedType) {
ParameterizedType pt=(ParameterizedType)t;
raw=(Class<?>)pt.getRawType();
Type[] param=raw.getTypeParameters();
Annotation[][] a = Arrays
.stream(((AnnotatedParameterizedType)at).getAnnotatedActualTypeArguments())
.map(AnnotatedType::getAnnotations)
.toArray(Annotation[][]::new);
if(raw==target) return a;
atArgAnnos=new HashMap<>(a.length);
for(int ix = 0; ix < a.length; ix++)
atArgAnnos.put(param[ix], a[ix]);
}
else throw new UnsupportedOperationException(
"type variables, wildcard or arrays are not supported");
raw.asSubclass(target);// throws if not assignable
for(AnnotatedType aift: target.isInterface()? raw.getAnnotatedInterfaces():
new AnnotatedType[]{raw.getAnnotatedSuperclass()}) {
Type ift=aift.getType();
if(ift==target) return new Annotation[typeParameters.length][0]; // raw
else {
AnnotatedParameterizedType ifpt = (AnnotatedParameterizedType)aift;
if(((ParameterizedType)ifpt.getType()).getRawType()!=target) continue;
return Arrays.stream(ifpt.getAnnotatedActualTypeArguments())
.map(ta -> atArgAnnos.getOrDefault(ta.getType(), ta.getAnnotations()))
.toArray(Annotation[][]::new);
}
}
throw new UnsupportedOperationException(
t.getTypeName()+" does not (directly) extend or implement "+target);
}
它也不处理类型变量,通配符类型或数组;它已经相当复杂了。但是它处理了你的问题的例子以及Map
的类型参数中的任何一个或两个都没有出现在字段类型的声明中的情况,例如。
interface AnotherExample<ID, KEY> extends Map<KEY, @Size(min=100) String> {
ID getId();
}
和
AnotherExample<String, @Size(min=42) String> field;
当具有类似interface I<X> extends Map<X,X> {}
和字段声明I<@Size(min=10) String> field;
的类型声明时,它也有效,因此注释适用于键和键类型。
返回的注释对应于指定类型的类型参数;它可以像:
一样使用System.out.print(field.getName()+"\t");
Annotation[][] a=getActualAnnotations(field.getAnnotatedType(), Map.class);
System.out.println("key: "+Arrays.toString(a[0])+", value: "+Arrays.toString(a[1]));