由于泛型在运行时被抹除,所以无法直接通过对象实例或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
网友评论