Spring4新特性(6):更好的Java泛型操作API

趙志強 8年前發布 | 38K 次閱讀 泛型 API Spring WebSocket 開發

隨著泛型用的越來越多,獲取泛型實際類型信息的需求也會出現,如果用原生API,需要很多步操作才能獲取到泛型,比如:

ParameterizedType parameterizedType = 
    (ParameterizedType) ABService.class.getGenericInterfaces()[0];
Type genericType = parameterizedType.getActualTypeArguments()[1];

Spring提供的ResolvableType API,提供了更加簡單易用的泛型操作支持,如:

ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
resolvableType1.as(Service.class).getGeneric(1).resolve()

對于獲取更復雜的泛型操作ResolvableType更加簡單。

假設我們的API是:

public interface Service<N, M> {
}

@org.springframework.stereotype.Service
public class ABService implements Service<A, B> {
}

@org.springframework.stereotype.Service
public class CDService implements Service<C, D> {
}

如上泛型類非常簡單。

1、得到類型的泛型信息

ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);

通過如上API,可以得到類型的ResolvableType,如果類型被Spring AOP進行了CGLIB代理,請使用ClassUtils.getUserClass(ABService.class)得到原始類型。

可以通過如下得到泛型參數的第1個位置(從0開始)的類型信息

resolvableType1.getInterfaces()[0].getGeneric(1).resolve()

因為我們泛型信息放在 Service<A, B> 上,所以需要resolvableType1.getInterfaces()[0]得到;

通過getGeneric(泛型參數索引)得到某個位置的泛型;

resolve()把實際泛型參數解析出來

2、得到字段級別的泛型信息

假設我們的字段如下:

@Autowired
    private Service<A, B> abService;
    @Autowired
    private Service<C, D> cdService;

    private List<List<String>> list;

    private Map<String, Map<String, Integer>> map;

    private List<String>[] array;

通過如下API可以得到字段級別的ResolvableType

ResolvableType resolvableType2 =
                ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "cdService"));

然后通過如下API得到Service<C, D>的第0個位置上的泛型實參類型,即C

resolvableType2.getGeneric(0).resolve()

比如 List<List<String>> list;是一種嵌套的泛型用例,我們可以通過如下操作獲取String類型:

ResolvableType resolvableType3 =
                ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "list"));
resolvableType3.getGeneric(0).getGeneric(0).resolve();

更簡單的寫法

resolvableType3.getGeneric(0, 0).resolve(); //List<List<String>> 即String

比如Map<String, Map<String, Integer>> map;我們想得到Integer,可以使用:

ResolvableType resolvableType4 =
                ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "map"));
resolvableType4.getGeneric(1).getGeneric(1).resolve();

更簡單的寫法

resolvableType4.getGeneric(1, 1).resolve()

3、得到方法返回值的泛型信息

假設我們的方法如下:

private HashMap<String, List<String>> method() {
    return null;
}

得到Map中的List中的String泛型實參:

ResolvableType resolvableType5 =
                ResolvableType.forMethodReturnType(ReflectionUtils.findMethod(GenricInjectTest.class, "method"));
resolvableType5.getGeneric(1, 0).resolve();

4、得到構造器參數的泛型信息

假設我們的構造器如下:

public Const(List<List<String>> list, Map<String, Map<String, Integer>> map) {
}

我們可以通過如下方式得到第1個參數( Map<String, Map<String, Integer>>)中的Integer:

ResolvableType resolvableType6 =
                ResolvableType.forConstructorParameter(ClassUtils.getConstructorIfAvailable(Const.class, List.class, Map.class), 1);
resolvableType6.getGeneric(1, 0).resolve();

5、得到數組組件類型的泛型信息

如對于private List<String>[] array; 可以通過如下方式獲取List的泛型實參String:

ResolvableType resolvableType7 =
                ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "array"));
resolvableType7.isArray();//判斷是否是數組
resolvableType7.getComponentType().getGeneric(0).resolve();

6、自定義泛型類型

ResolvableType resolvableType8 = ResolvableType.forClassWithGenerics(List.class, String.class);
        ResolvableType resolvableType9 = ResolvableType.forArrayComponent(resolvableType8);
resolvableType9.getComponentType().getGeneric(0).resolve();

ResolvableType.forClassWithGenerics(List.class, String.class)相當于創建一個List<String>類型;

ResolvableType.forArrayComponent(resolvableType8);:相當于創建一個List<String>[]數組;

resolvableType9.getComponentType().getGeneric(0).resolve():得到相應的泛型信息;

7、泛型等價比較:

resolvableType7.isAssignableFrom(resolvableType9)

如下創建一個List<Integer>[]數組,與之前的List<String>[]數組比較,將返回false。

ResolvableType resolvableType10 = ResolvableType.forClassWithGenerics(List.class, Integer.class);
ResolvableType resolvableType11= ResolvableType.forArrayComponent(resolvableType10);
resolvableType11.getComponentType().getGeneric(0).resolve();
resolvableType7.isAssignableFrom(resolvableType11);

從如上操作可以看出其泛型操作功能十分完善,尤其在嵌套的泛型信息獲取上相當簡潔。目前整個Spring4環境都使用這個API來操作泛型信息。

如之前說的泛型注入: Spring4新特性——泛型限定式依賴注入 ,通過在依賴注入時使用如下類實現:

GenericTypeAwareAutowireCandidateResolver

QualifierAnnotationAutowireCandidateResolver

ContextAnnotationAutowireCandidateResolver

還有如Spring的核心BeanWrapperImpl,以及整個Spring/SpringWevMVC的泛型操作都是替換為這個API了:GenericCollectionTypeResolver和GenericTypeResolver都直接委托給ResolvableType這個API。

所以大家以后對泛型操作可以全部使用這個API了,非常好用。測試用例請參考 GenricInjectTest.java

來自: http://www.importnew.com/19185.html

 

 本文由用戶 趙志強 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!