百日筑基第五十天-TypeReference-FastJson详解
TypeReference是一个描述复杂泛型的工具类。很多类库都有,我们使用alibaba.fastjson来举例。
在反序列化场景中获取泛型参数。
TypeReference支持泛型参数,方便一些框架实现通用的反序列化类,对复杂的类型可以很方便的反序列化。
使用Gson、Jackson或Fastjson反序列化泛型时,需要传递泛型的真实类型,所以一般都通过集成TypeReference来实现。
简单示例
@Slf4j(topic = "juc")
public class TypeRefrenceStudy {
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 3, 4, 8, 9);
JSONObject jsonObject = new JSONObject();
jsonObject.put("list", list);
log.info(jsonObject.toString());
// 使用匿名类创建TypeReference的子类对象
List<Integer> list2 = jsonObject.getObject("list", new TypeReference<List<Integer>>() {});
log.info("list2 {}", list2);
}
}
执行结果:
16:07:37.122 [main] juc - {"list":[1,3,4,8,9]}
16:07:37.141 [main] juc - list2 [1, 3, 4, 8, 9]
- 使用TypeReference可以明确指定反序列化的类型,能够比较方便的获取反序列化的数据。
复杂示例
例子:
Response response = JSONObject.parseObject(result, new TypeReference<Response>(TaskCodeRespData.class) {});
等价于:
Response response = JSONObject.parseObject(result, new TypeReference<Response>( ) {})
如果要用泛型变量 ,有参数的写法就相当必要了。
单参数例子
public class Response {
public T data;
}
public static Response parseToMap(String json, Class type) {
return JSON.parseObject(json, new TypeReference<Response>(type) {});
}
双参数例子
public static <K, V> Map<K, V> parseToMap(String json, Class keyType, Class valueType) {
return JSON.parseObject(json, new TypeReference<Map<K, V>>(keyType, valueType) {});
}
// 可以这样使用
String json = “{1:{name:“ddd”},2:{name:“zzz”}}”;
Map<Integer, Model> map = parseToMap(json, Integer.class, Model.class);
assertEquals(“ddd”, map.get(1).name);
assertEquals(“zzz”, map.get(2).name);
一个重要实战样例
Json字符串:
[{
"id": null,
"name": " ",
"age": 500,
"gender": false,
"email": "email",
"employed": true,
"salary": 10
}]
UserResource实体类:
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserResource {
private UUID id;
private String name;
private int age;
private boolean gender;
private String email;
private boolean employed;
private BigDecimal salary;
}
理想的实现方式
理想的实现方式是告诉ObjectMapper
的readValue
方法,我要的是List<UserResource>
,帮我反序列化成这个类型。
List<UserResource> list = new ObjectMapper().readValue(userResourcesStr, List<UserResource>.class);
现实是编译器告诉你这不行,Cannot select from parameterized type
. 也很好理解,Java编译器认为List是Class,而List则不是。
既然不能用List<UserResource>.class
, 那如果我告诉ObjectMapper
的readValue
方法,我要的是List
类型,但返回值类型是List<UserResource>
, 会发生什么呢?
List<UserResource> list = new ObjectMapper().readValue(userResourcesStr, List.class);
这时候倒没有编译错误, 但是会有警告:Unchecked assignment: 'java.util.List' to 'java.util.List<UserResource>'
, 显然ObjectMapper并不能反序列化为UserResource类型,而是LinkedHashMap类型。
TypeReference的实现方式
ObjectMapper提供了readValue(String content, TypeReference valueTypeRef)
接口,第二个参数为new一个TypeReference
的子类实例:new TypeReference<List<UserResource>>(){}
。泛型抽象类TypeReference用于通过子类获取完整的泛型类型信息。
public <T> T readValue(String content, TypeReference valueTypeRef)
List<UserResource> list = new ObjectMapper().readValue(userResourcesStr, new TypeReference<List<UserResource>>(){});