背景
开发过程中,我们为了减少错误发生,会将很多异常数据返回默认值,如Gson反序列化,我们加工后 ,即使传入空json和Type,其fromJson的返回均能返回默认值。但是维护的基础库发生异常。java.lang.ClassCastException: com.google.gson.internal.GsonGsonGsonTypes$ParameterizedTypeI cannot be cast to java.lang.Class。因使用了((Class<?>) type).newInstance()获取默认值, 将所有类型type强转为class导致错误。
Object obj = gson.fromJson(json, type);
return null == obj ? (T) ((Class<?>) type).newInstance() : (T) obj ;// 强转类型错误
原理
- Object:
Object 是一个类。 每个类都继承自 Object,所有对象(包括数组)都实现了这个类的方法。
- Class:
Class 是一个类(不是class)。该类没有公共构造函数,相反,类对象由Java虚拟机自动构建,用于表示JVM运行时类或接口的信息。Class类的构造函数被设计为私有的,这意味着我们不能通过new的方式来创建Class对象,只有JVM才能创建该类的实例。
- Type:
Type 是一个接口。Type是Java编程语言中所有类型的通用超级接口,这些包括:
- 原始类型(raw types):包括类和接口。基本数据类型和不涉及泛型的所有引用类型(类、接口、数组)均是Class类型。比如String
s、String s1[]、List list等对应的类型均是Class类型。 - 参数化类型(parameterized types):也叫泛型,例如List是一个参数化类型。Map<String,Integer> map 等对应的类型均是ParameterizedType类型
- 数组类型(array types):带有泛型的数组类型,也就是带有参数化类或者接口所表示的数组对应的类型,例如 List s[]、Map<String,Integer> map[]等对应的类型均是GenericArrayType类型,而List s[]、Map map[]是Class类型
- 类型变量(type variables):也叫泛型变量,即泛型中的变量,例如:T、K、V等变量,可以表示任何类。
- 基本数据类型(primitive types):byte、short、boolean、char、int、long、float、double
八大基本数据类型。 - 通配符类型(WildcardType) :通配符对应的类型,例如 List<? extends Object> 中?对应的类型
如果我们使用普通的java bean类,那是class类型,可以强转,但是参数化类型 不同于class。
ParameterizedType就是参数化类型的意思
声明类型中带有“<>”的都是参数化类型,比如List,Map<String,Long>
- getActualTypeArguments()返回Type[],即“<>”里的参数,比如Map<String,Integer>
- getRawType()返回Tpye,得到“<>”前面的类型,比如List
- getOwnerType()返回Type,返回ParameterizedType类型所在的类的Type。如Map.Entry<String,
Object>这个参数化类型返回的是Map(因为Map.Entry这个类型所在的类是Map)的类型。
方案
为了达到gson反序列化传空json也能返回默认值的目的,针对ParameterizedType这种情况。
参数化类型List不是Class类型,强转会异常,不能返回默认初始对象,可利用空的泛型gson.toJson后的结果(gson。toJson(new ArrayList())输出‘[]’),反向用fromJson默认值作为json为空时的默认值。
适配了List<> Map<> Set<>(忽略泛型类型)三种泛型为空时的json输出
private static <T> T getDefaultValueWithType (Type type) throws IllegalAccessException, InstantiationException {
if(typeinstanceof Class) {
return (T) ((Class<?>) type).newInstance();
} else if (type instanceof ParameterizedType) {
//泛型类型默认值
ParameterizedType genericType = (ParameterizedType) type;
if (genericType.getRawType().equals(List.class) ||
genericType.getRawType().equals(Set.class)) {
return gson.fromJson("[]", type);
} else if(genericType.getRawType().equals(Map.class)) {
return gson.fromJson("{}", type);
} else {
return null;
}
} else {
return null;
}
}
//测试时,封装过后的gson工具类
Map<String, Integer> test= GsonTool.fromJson(null, (new TypeToken<Map<String, Integer>>() {}).getType());
//fromJson 内部调用getDefaultValueWithType 返回默认初始化值
System.out.println("get default obj size "+test.size() + " " + GSON.toJson(test));
其他不常用类型默认返回null
本文探讨了在Java开发中处理ParameterizedType类型时如何设置默认值,尤其是在Gson反序列化中遇到的问题。文章指出,直接将ParameterizedType转换为Class会导致ClassCastException。解释了Object、Class和Type接口的区别,并详细阐述了ParameterizedType的原理。为了解决这个问题,提出了使用空泛型对象的json表示(如'[]')作为默认值的解决方案,以适配List、Map和Set三种泛型类型的空值情况。

3万+

被折叠的 条评论
为什么被折叠?



