2016-11-24 69 views
1

要有延伸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註釋已給出K類型參數java.util.Map

我知道如何從字段的AnnotatedParameterizedType獲得類型參數的註釋,但是我錯過了如何將這與超類型Map的類型參數相關聯。

回答

1

不幸的是,這遠非易事。以下代碼假設您想要查找類型爲的註釋,直接實現或擴展該類型,否則代碼將變得更加複雜,或者對於多次間接實現的接口產生歧義問題。

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]));