当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) {
        this.code = 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 = JSONObject.toJavaObject(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 = JSONObject.toJavaObject(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();
        array.add(a);
        jsonObject.put("listBean", array);

        TestBean<A> testBean = JSONObject.toJavaObject(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) {
        this.code = code;
    }

    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.println(testBean.getListBean().get(0).getName());

控制台报错:

Exception in thread "main" java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.zhw.free.zhwfreedemo.testjson.A
	at com.zhw.free.zhwfreedemo.testjson.Test1.main(Test1.java:30)

报了类转换异常,提示JSONObject 无法转换为我们刚刚定义的A,这是为什么呢?

  • Debug看一下究竟
    debug阶梯

原来JSONObject帮我们反序列化后,集合中依然是JSONObject。这里就要说说Java 的泛型的类型擦除了。

在反序列化为TestBean的时候,JSONObject并不知道listBean集合中存放的类型是什么,但是依然可以转换成功。这就是泛型的类型擦除的功劳。泛型的类型擦除机制方便了我们,但也给我们反序列化时留下了思考,如何让JSON反序列化时知道我们泛型中的类型是什么呢?

  • 王者
        TestBean<A> result = jsonObject.toJavaObject(new TypeReference<TestBean<A>>() {});
        System.out.println(result);
        System.out.println(result.getListBean().get(0).getName());

利用TypeReference 指定泛型中的类型, 就可以顺利反序列化成功,并且 集合中的对象也转换过来了。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LinkList是Java中的链表数据结构,它的特点是每个节点中都包含指向下一个节点的引用。Hash Map是Java中的散列表数据结构,它通过将键映射到值的方式来存储和访问元素。ObjectMapper是Jackson库中的一个类,用于将JSON数据反序列化Java对象。 当需要将JSON数据反序列化为LinkList或Hash Map对象时,可以使用ObjectMapper类的readValue方法。该方法接受两个参数,第一个参数是要反序列化JSON数据,第二个参数是要生成的目标对象类型。例如,以下是将JSON数据反序列化为LinkList对象的示例代码: ``` String json = "[1, 2, 3]"; ObjectMapper objectMapper = new ObjectMapper(); LinkList<Integer> list = objectMapper.readValue(json, new TypeReference<LinkList<Integer>>(){}); ``` 在上面的代码中,json变量表示要反序列化JSON数据。然后,我们创建了一个ObjectMapper对象,并使用其readValue方法来将json反序列化为LinkList<Integer>对象。由于泛型在运行时会被擦除,因此我们需要使用TypeReference类来指定反序列化的目标类型。 同样地,我们也可以将JSON数据反序列化为Hash Map对象。以下是示例代码: ``` String json = "{\"key1\":\"value1\", \"key2\":\"value2\"}"; ObjectMapper objectMapper = new ObjectMapper(); Hash Map<String, String> map = objectMapper.readValue(json, new TypeReference<Hash Map<String, String>>(){}); ``` 在上面的代码中,json变量表示要反序列化JSON数据。然后,我们创建了一个ObjectMapper对象,并使用其readValue方法将json反序列化为Hash Map<String, String>对象。 总结来说,通过使用ObjectMapper类的readValue方法,我们可以将JSON数据反序列化为LinkList或Hash Map对象,从而方便地进行后续的操作和处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值