作者: @怪盜kidou
如需轉(zhuǎn)載需在明顯位置保留作者信息及原文鏈接
如果博客中有不恰當(dāng)之處歡迎留言交流
http://www.reibang.com/p/d62c2be60617
在你真的會(huì)用Gson嗎?Gson使用指南(一) 的第三節(jié)我介紹了在Gson中如何使用泛型來(lái)簡(jiǎn)化我們的類(lèi)設(shè)計(jì)锯七,但隨之而來(lái)引入了一個(gè)新的問(wèn)題:封裝。不知道各位有沒(méi)有想過(guò)這樣一個(gè)問(wèn)題:每次都要用 new TypeToken<XXX>(){};
好麻煩域蜗,有沒(méi)有更好的辦法?
有更好的辦法么?當(dāng)然有霉祸!相信也有不少人自己作了嘗試丝蹭,只是有人歡喜有人愁了半夷,不過(guò)沒(méi)關(guān)系迅细,今天我們就來(lái)解決這個(gè)問(wèn)題茵典。
約定
1统阿、本文涉及到的json格式
// data 為 object 的情況
{"code":"0","message":"success","data":{}}
// data 為 array 的情況
{"code":"0","message":"success","data":[]}
2、假定第一種的對(duì)應(yīng)的Java類(lèi)型為 Result<XXX>
帆离,第二種為 Result<List<XXX>>
一结澄、為何封裝麻献,如何封裝
1们妥、為何封裝:
- 寫(xiě)
new TypeToken<XXX>(){}
麻煩监婶,IDE格式化后還不好看 - 不同的地方每進(jìn)行一次
new TypeToken<XXX>(){}
操作都會(huì)生成一個(gè)新的類(lèi) - 對(duì)于任意類(lèi)
XXX
都只有兩種情況new TypeToken<Result<XXX>>(){}
和new TypeToken<Result<List<XXX>>>(){}
- 方便統(tǒng)一管理
2惑惶、如何封裝
從上面的我們可以知道集惋,最簡(jiǎn)單的方法就是提供兩個(gè)方法分別對(duì)應(yīng)data
為Array和Object的情況并接收一個(gè)參數(shù)踩娘,即告知XXX的類(lèi)型养渴,自動(dòng)將完成new TypeToken<XXX>(){}
與new TypeToken<Result<List<XXX>>>(){}
的過(guò)程理卑。
方法原型:
// 處理 data 為 object 的情況
public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {}
// 處理 data 為 array 的情況
public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz){}
二、為何失敗?
對(duì)于那些嘗試著封裝過(guò)的人可能都這么寫(xiě)過(guò):
public static <T> Result<List<T>> fromJsonArray(Reader reader) {
Type type = new TypeToken<Result<List<T>>>(){}.getType();
return GSON.fromJson(reader, type);
}
當(dāng)然上面的寫(xiě)法肯定是沒(méi)有辦法完成的,雖然代碼不會(huì)報(bào)錯(cuò),但運(yùn)行結(jié)果肯定是不對(duì)的自赔,因?yàn)檫@里的T
其實(shí)是一個(gè) TypeVariable
绍妨,他在運(yùn)行時(shí)并不會(huì)變成我們想要的XXX柬脸,所以通過(guò)TypeToken
得到的 泛型信息只是 "Result<List<T>>"
他去。
三、如何解決?
既然TypeToken的作用是用于獲取泛型的類(lèi)灾测,返回的類(lèi)型為Type
行施,真正的泛型信息就是放在這個(gè)Type
里面蛾号,既然用TypeToken生成會(huì)有問(wèn)題,那我們自己生成Type就行了嘛涯雅。
Type是Java中所有類(lèi)型的父接口,在1.8以前是一個(gè)空接口活逆,自1.8起多了個(gè)getTypeName()
方法蔗候,下面有ParameterizedType
锈遥、 GenericArrayType
所灸、 WildcardType
爬立、 TypeVariable
幾個(gè)接口,以及Class
類(lèi)奕巍。這幾個(gè)接口在本次封裝過(guò)程中只會(huì)用到 ParameterizedType
,所以簡(jiǎn)單說(shuō)一下:
ParameterizedType
簡(jiǎn)單說(shuō)來(lái)就是形如“ 類(lèi)型<> ”的類(lèi)型,如:Map<String,User>
。下面就以 Map<String,User>
為例講一下里面各個(gè)方法的作用憋沿。
public interface ParameterizedType extends Type {
// 返回Map<String,User>里的String和User,所以這里返回[String.class,User.clas]
Type[] getActualTypeArguments();
// Map<String,User>里的Map,所以返回值是Map.class
Type getRawType();
// 用于這個(gè)泛型上中包含了內(nèi)部類(lèi)的情況,一般返回null
Type getOwnerType();
}
所以,知道了這里需要的泛型是怎么回事砸民,一切都好說(shuō)了奋救,下面我們來(lái)完成之前留下的空方法岭参。
1、實(shí)現(xiàn)一個(gè)簡(jiǎn)易的 ParameterizedType
public class ParameterizedTypeImpl implements ParameterizedType {
private final Class raw;
private final Type[] args;
public ParameterizedTypeImpl(Class raw, Type[] args) {
this.raw = raw;
this.args = args != null ? args : new Type[0];
}
@Override
public Type[] getActualTypeArguments() {
return args;
}
@Override
public Type getRawType() {
return raw;
}
@Override
public Type getOwnerType() {return null;}
}
2、生成Gson需要的泛型
2.1解析data是object的情況
public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {
Type type = new ParameterizedTypeImpl(Result.class, new Class[]{clazz});
return GSON.fromJson(reader, type);
}
2.2解析data是array的情況
是Array的情況要比是Object的情況多那么一步狡汉。
public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz) {
// 生成List<T> 中的 List<T>
Type listType = new ParameterizedTypeImpl(List.class, new Class[]{clazz});
// 根據(jù)List<T>生成完整的Result<List<T>>
Type type = new ParameterizedTypeImpl(Result.class, new Type[]{listType});
return GSON.fromJson(reader, type);
}
本次代碼較少捻脖,不提供源碼
雖然這篇博客是以Gson為例援雇,但從上面的內(nèi)容可以看出實(shí)際上和Gson關(guān)系不大筐赔,主要的內(nèi)容還是Java的泛型基礎(chǔ)天吓,所以這種封裝的方法同樣適用于其它的框架龄寞。
最后借這次機(jī)會(huì)給安利一個(gè)簡(jiǎn)易的泛型生成庫(kù) TypeBuilder 汰规,其最初實(shí)現(xiàn)的目的就是讓大家快速的生成泛型信息,同時(shí)也會(huì)作一些參數(shù)檢查物邑,保證正確性控轿。
用上面的代碼給大家舉個(gè)例子
public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz) {
Type type = TypeBuilder
.newInstance(Result.class)
.beginSubType(List.class)
.addTypeParam(clazz)
.endSubType()
.build();
return GSON.fromJson(reader, type);
}
public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {
Type type = TypeBuilder
.newInstance(Result.class)
.addTypeParam(clazz)
.build();
return GSON.fromJson(reader, type);
}
我最近剛剛開(kāi)通了微信公眾號(hào)(怪盜kidou),歡迎關(guān)注