fastjson 泛型转换问题(详解)

系列文章目录

附属文章一:fastjson TypeReference 泛型类型(详解)


文章目录

  • 系列文章目录
  • 前言
  • 一、代码演示
    • [1. 不存在泛型转换](#1. 不存在泛型转换)
    • [2. 存在泛型转换](#2. 存在泛型转换)
    • [3. 存在泛型集合转换](#3. 存在泛型集合转换)
  • 二、原因分析
  • 三、解决方案
    • [1. 方案1:重新执行泛型的 json 转换](#1. 方案1:重新执行泛型的 json 转换)
    • [2. 方案2:使用 TypeReference 指定泛型类型](#2. 方案2:使用 TypeReference 指定泛型类型)

前言

本文讲解使用 fastjson 进行 json 转换泛型 T、泛型集合 R<List>、或者子类中的泛型、或者多层泛型,存在的 json 转换异常报错问题,以及解决方案。


一、代码演示

data 实际对象类型:

java 复制代码
@Data
public class SysUser {

    String userId;

    String userName;
}

1. 不存在泛型转换

响应类:

java 复制代码
@Data
public class R {

    Integer code;

    String msg;

    SysUser data;
}

测试类:

java 复制代码
@Slf4j
public class Test {

    public static void main(String[] args) {
        String jsonStr = "{\"code\":0,\"msg\":\"操作成功\",\"data\":{\"userId\":\"1001\",\"userName\":\"小白\"}}";
        R rSysUser = JSONObject.parseObject(jsonStr, R.class);
        SysUser sysUser = rSysUser.getData();
        log.info("sysUser={}", sysUser.toString());
    }
}

执行上述代码,结果如下:

通过断点调试可以看到 JSONObject.parseObject(jsonStr, R.class) 转换后的对象中的子对象的实际类型为 SysUser,数据为等值的形式。

2. 存在泛型转换

泛型响应类:

java 复制代码
@Data
public class R<T> {

    Integer code;

    String msg;

    T data;
}

泛型测试类:

java 复制代码
@Slf4j
public class Test {

    public static void main(String[] args) {
        String jsonStr = "{\"code\":0,\"msg\":\"操作成功\",\"data\":{\"userId\":\"1001\",\"userName\":\"小白\"}}";
        R<SysUser> rSysUser = JSONObject.parseObject(jsonStr, R.class);
        SysUser sysUser = rSysUser.getData();
        log.info("sysUser={}", sysUser.toString());
    }
}

执行上述代码,结果如下:

通过断点调试可以看到 JSONObject.parseObject(jsonStr, R.class) 转换后的对象中的子泛型对象的实际类型为 JSONObject,数据为 key-value 的形式。

此时往下执行,进行 JSONObject 和 SysUser 对象的直接赋值,就会抛出异常:

3. 存在泛型集合转换

泛型集合测试类:

java 复制代码
@Slf4j
public class Test {

    public static void main(String[] args) {
        String jsonStr = "{\"code\":0,\"msg\":\"操作成功\",\"data\":[{\"userId\":\"1001\",\"userName\":\"小白\"}]}";
        R<List<SysUser>> rSysUser = JSONObject.parseObject(jsonStr, R.class);
        List<SysUser> sysUserList = rSysUser.getData();
        log.info("sysUserList={}", sysUserList.toString());
        SysUser sysUser = sysUserList.get(0);
        log.info("sysUser={}", sysUser.toString());
    }
}

执行上述代码,结果如下:

通过断点调试可以看到 JSONObject.parseObject(jsonStr, R.class) 转换后的对象中的泛型集合对象的实际类型为 JSONObject,数据为 key-value 的形式。

此时往下执行,进行 JSONObject 和 SysUser 对象的直接赋值,就会抛出异常:

扩展:

当然,泛型 T、泛型集合 R<List>、或者子类中的泛型、或者多层泛型,都存在同样的问题。本文不再演示。

二、原因分析

因为当 json 转换的对象是泛型时,我们无法获取到实际的类,无法获取到类的变量,也无法获取到类变量的 get、set 方法,所以我们无法将这个 json 数据转换到某一个实际的类对象中存储,所以 com.alibaba.fastjson 会临时转换为 JSONObject 对象,以 key-value 形式存储。

这样就存在一个问题,当我们将该泛型对象赋值转换为实际的类对象时,就会因类型不匹配而抛出异常。

三、解决方案

1. 方案1:重新执行泛型的 json 转换

将泛型转换为 json 字符串后,重新进行类对象转换。

泛型转换:

java 复制代码
R<SysUser> rSysUser = JSONObject.parseObject(jsonStr, R.class);
SysUser sysUser = JSONObject.parseObject(JSONObject.toJSONString(rSysUser.getData()), SysUser.class);

泛型集合转换:

java 复制代码
R<List<SysUser>> rSysUser = JSONObject.parseObject(jsonStr, R.class);
List<SysUser> sysUserList = JSONObject.parseArray(JSONObject.toJSONString(rSysUser.getData()), SysUser.class);

2. 方案2:使用 TypeReference 指定泛型类型

使用 fastjson 的 TypeReference 来指定泛型类型。

在指定了 json 转换中泛型的实际类型后,就能获取到实际的类,获取到类的变量,获取到类变量的 get、set 方法,从而将泛型的 json 转换成实际的类对象。

本文不过多讲解 TypeReference 类,详细了解请转 《fastjson TypeReference 泛型类型(详解)》https://editor.csdn.net/md/?articleId=139363645

泛型转换:

java 复制代码
R<SysUser> rSysUser = JSONObject.parseObject(jsonStr, new TypeReference<R<SysUser>>(){});
SysUser sysUser = rSysUser.getData();

泛型集合转换:

java 复制代码
R<List<SysUser>> rSysUser = JSONObject.parseObject(jsonStr, new TypeReference<R<List<SysUser>>>(){});
List<SysUser> sysUserList = rSysUser.getData();
相关推荐
脸红ฅฅ*的思春期7 天前
Java安全—log4j日志&FastJson序列化&JNDI注入
java·安全·log4j·fastjson·jndi注入
人在码中跑_发在天上飞18 天前
【工具类】理解 TypeUtils 类:深入解析 FastJSON 的类型转换工具
java·工具类·fastjson
爱吃土豆的程序员1 个月前
java List<Map<String, Object>> 转 List<JSONObject> 的几种方式
java·list·stream·jsonobject·集合转换
M1A11 个月前
高性能 JSON 处理:为何选择 Fastjson?
json·fastjson
uhfun1 个月前
Fastjson json字符串怎样直接反序列化为对象
后端·fastjson
uccs1 个月前
Spring Boot 配置 FastJson
java·spring boot·fastjson
招风的黑耳3 个月前
fastjson序列化时过滤字段的方法
fastjson·java序列化·过滤字段
未完成的歌~3 个月前
Fastjson漏洞分析与复现
fastjson
burg_xun3 个月前
一次日志记录中使用fastjson涉及到ByteBuffer的教训
java·fastjson
车海滨4 个月前
04-Fastjson反序列化漏洞
网络安全·中间件·fastjson