泛型的反序列化

简化问题

日常使用过程中,我们经常碰到泛型的序列化Json,但是有时候我们需要把一个Json反序列化成一个泛型对象,怎么做,你可能会想到这样做,例如在Gson中

1
Gson().fromJson<List<String>>(JsonString, List<String>::class.java)

但是你这样写,其实会遇到一个错误 ** Only classes are allowed on the left hand side of a class literal**
image.png
为什么会这样,因为泛型有类型擦除,泛型其实只是在编译的存在,运行的时候是不存在的,而反序列化需要再运行的时候获取到具体的类型,而类型却被擦除了,所以会报错,那么怎么办?

泛型怎么反序列化成对象?

看函数的参数类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//这里要的是个class
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
// 都转成到这里
T object = fromJson(json, TypeToken.get(classOfT));
return Primitives.wrap(classOfT).cast(object);
}


// 其实需要的是一个TypeToken
public <T> T fromJson(String json, TypeToken<T> typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
StringReader reader = new StringReader(json);
return fromJson(reader, typeOfT);
}

TypeToken实际上是私有的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TypeToken<T> {
@SuppressWarnings("unchecked")
protected TypeToken() {
this.type = getTypeTokenTypeArgument();
this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
this.hashCode = type.hashCode();
}

@SuppressWarnings("unchecked")
private TypeToken(Type type) {
this.type = $Gson$Types.canonicalize(Objects.requireNonNull(type));
this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
}

我们可以通过构造Type来达到目的, 但是这个Type是接口,我们需要构造ParameterizedType

1
2
3
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
return (T) fromJson(json, TypeToken.get(typeOfT));
}
1
2
3
4
5
6
7
8
9
10
11
fun main(args: Array<String>) {
Gson().fromJson<List<String>>("JsonString", getType(List::class.java, String::class.java))
}
fun getType(raw: Class<*>, vararg args: Type) = object : ParameterizedType {
//原始类型,例如List<String>,整体看来就是List
override fun getRawType(): Type = raw
// 泛型 参数,例如有多个
override fun getActualTypeArguments(): Array<out Type> = args
//顶层类就是null,Type 对象,表示此类型是其成员之一的类型,例如Map接口就是Map.Entry的OwnerType.
override fun getOwnerType(): Type? = null
}

如果有多重泛型怎么写,getType可以嵌套调用的,通过Type构成Type

1
2
//List<List<String>>
getType(List::class.java, getType(List::class.java, String::class.java))