当Java泛型擦除遇到JSON序列化和反序列化
当Java泛型类型擦除遇到JSON序列化和反序列化
⽬录
前⾔
-最近看到了Spring 关于 RestTemplate的源码实现⼜有了⼀些思考,突然想到之前⾃⼰处理过这样的场景,这次整理⼀篇⽂章⽔⼀下⼦,哈哈哈哈。先抛出问题:
如果让你让对复杂JSON对象转为Java Bean你会怎么写?
-要转换的Java Bean 中有泛型,⼜要怎么转?
本次重点我们放在JSON 反序列化时如何正确告诉Java 运⾏时,泛型中具体的类型是什么。
测试
源于⼯作中遇到的⼀个场景,使⽤httpClient 调⽤其他服务的接⼝,想要把Response 的body 中的JSON 格式的字符串反序列化为Java Bean。
测试⽤的Java Bean:
class TestBean {
private String name;
private String code;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
}
@Override
public String toString() {
return "TestBean{" +
"name='" + name + '\'' +
", code='" + code + '\'' +
'}';
}
}
青铜
public static void main(String[] args) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "aaa");
jsonObject.put("code", "123");
TestBean testBean = JavaObject(jsonObject, TestBean.class);
System.out.println(testBean);
}
控制台打印:
TestBean{name='aaa', code='123'}
黄⾦
这次在TestBean 添加属性 List<T> listBean;
public class Test1 {
public static void main(String[] args) {
/* JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "aaa");
jsonObject.put("code", "123");
TestBean testBean = JavaObject(jsonObject, TestBean.class);
System.out.println(testBean);*/
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "aaa");
jsonObject.put("code", "123");
JSONObject a = new JSONObject();
a.put("id", 1);
a.put("name", "属性a");
JSONArray array = new JSONArray();
object toarray.add(a);
jsonObject.put("listBean", array);
TestBean<A> testBean = JavaObject(jsonObject, TestBean.class); System.out.println(testBean);
}
}
class TestBean<T> {
private String name;
private String code;
List<T> listBean;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
}
public List<T> getListBean() {
public List<T> getListBean() {
return listBean;
}
public void setListBean(List<T> listBean) {
this.listBean = listBean;
}
@Override
public String toString() {
return "TestBean{" +
"name='" + name + '\'' +
", code='" + code + '\'' +
", listBean=" + listBean +
'}';
}
}
class A {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "A{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
控制台打印:
TestBean{name='aaa', code='123', listBean=[{"name":"属性a","id":1}]}
遇到了绊脚⽯
我们打印⼀下 listBean 集合中对象的属性name
System.out.ListBean().get(0).getName());
控制台报错:
Exception in thread "main" java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.zhw.stjson.A at com.zhw.stjson.Test1.main(Test1.java:30)
报了类转换异常,提⽰JSONObject ⽆法转换为我们刚刚定义的A,这是为什么呢?
Debug看⼀下究竟
原来JSONObject帮我们反序列化后,集合中依然是JSONObject。这⾥就要说说Java 的泛型的类型擦除了。
在反序列化为TestBean的时候,JSONObject并不知道listBean集合中存放的类型是什么,但是依然可以转换成功。这就是泛型的类型擦除的功劳。泛型的类型擦除机制⽅便了我们,但也给我们反序列化时留下了思考,如何让JSON反序列化时知道我们泛型中的类型是什么呢?
王者
TestBean<A> result = JavaObject(new TypeReference<TestBean<A>>() {});
System.out.println(result);
System.out.ListBean().get(0).getName());
利⽤TypeReference 指定泛型中的类型, 就可以顺序反序列化成功,并且 集合中的对象也转换过来了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论