系列文章目录
附属文章一: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();