由於泛型在運行時被抹除,所以無法直接通過對象實例或class獲取,在老版本的Gson里可以通過一下方法獲取實際類型:
Type type = new TypeToken<Test>(){}.getType();
但是Gson 2.8.6內TypeToken構造方法已經不再公開:
解決方案:
- 使用Gson提供的創建TypeToken的公開靜態方法:
- 通過自定義Type類,將泛型內容寫進去
public class ParameterizedTypeImpl implements ParameterizedType {
@Nullable
private final Type ownerType;
private final Type rawType;
private final Type[] typeArguments;
public ParameterizedTypeImpl(@Nullable Type ownerType, Type rawType, Type... typeArguments) {
// Require an owner type if the raw type needs it.
if (rawType instanceof Class<?>
&& (ownerType == null) != (((Class<?>) rawType).getEnclosingClass() == null)) {
throw new IllegalArgumentException();
}
for (Type typeArgument : typeArguments) {
Objects.requireNonNull(typeArgument, "typeArgument == null");
TypeUtil.checkNotPrimitive(typeArgument);
}
this.ownerType = ownerType;
this.rawType = rawType;
this.typeArguments = typeArguments.clone();
}
@NonNull
@Override
public Type[] getActualTypeArguments() {
return typeArguments.clone();
}
@NonNull
@Override
public Type getRawType() {
return rawType;
}
@Override
public @Nullable
Type getOwnerType() {
return ownerType;
}
@Override
public boolean equals(Object other) {
return other instanceof ParameterizedType && TypeUtil.equals(this, (ParameterizedType) other);
}
@Override
public int hashCode() {
return Arrays.hashCode(typeArguments)
^ rawType.hashCode()
^ (ownerType != null ? ownerType.hashCode() : 0);
}
@NonNull
@Override
public String toString() {
if (typeArguments.length == 0) return TypeUtil.typeToString(rawType);
StringBuilder result = new StringBuilder(30 * (typeArguments.length + 1));
result.append(TypeUtil.typeToString(rawType));
result.append("<").append(TypeUtil.typeToString(typeArguments[0]));
for (int i = 1; i < typeArguments.length; i++) {
result.append(", ").append(TypeUtil.typeToString(typeArguments[i]));
}
return result.append(">").toString();
}
}
上述2種方法本質上都是創建自定義Type,將泛型信息保存在內,差別在與方案2代碼來自retrofit2,不需要額外依賴。
2020-03-03