Json是开发过程中饶过不去的一种格式,而且这种格式非常的通用。
而FastJson2 是一种使用广泛的解析工具,对于一些工具、框架性质的类,又经常不可避免的需要使用到Java的泛型,本文就简单记录下泛型场景下,JSON的数据处理解析。
主要解决Fastjson解析泛型,嵌套类型等。
常用的交互模型
先介绍下一般常用的交互格式(请求响应类似的道理,以响应举例):
一种非常常见的格式化模板代码为:
public class ResponseBean<RS> {
private Integer code;
private String msg;
private RS data;
}
对应的Json串的形式如下,其中data节点也可能没有,也可能嵌套多层:
{
"code":1,
"msg":"成功",
"data": {
...........
}
}
响应返回的分类
(1)最基础格式,没有嵌套,单纯地字段与对应的值,返回请求与响应,也可能包含更多的一些其他字段
{
"code": 1,
"msg": "成功"
}
(2)稍微复杂点,对象层次的嵌套,不涉及到List<>
也就是没有数组。
从类设计的视角看,包含了一个对象,这个对象包含两个属性
{
"code":1,
"msg":"成功",
"data": {
"position": 1,
"show": true
}
}
(3)返回字段与List<>
,并且通常使用data
作为对象的key,也就是返回码、返回消息单独字段,数据体包含在data中,并且
{
"code": 1,
"msg": "识别成功",
"data": [
{
"positionId": 1,
"x1": 0,
"y1": 0,
"x2": 200,
"y2": 200
},
{
"positionId": 2,
"x1": 5,
"y1": 10,
"x2": 36,
"y2": 21
},
{
"positionId": 3,
"x1": 44,
"y1": 55,
"x2": 66,
"y2": 77
},
{
"positionId": 4,
"x1": 24,
"y1": 22,
"x2": 58,
"y2": 96
}
]
}
按照通用的交互式逻辑开发的话,返回的响应基本上就是这样几种格式,无非是data
中样式的不断变化。
FastJson 对这些形式的解析,都是完全没有问题的,重点是与泛型纠缠在一起的时候,如何能够根据实际类型进行解析。
通用泛型解析
下面示例记录下一种通用的解决方式,以及子类父类泛型的解析处理。
RequestBean
和 ResponseBean
是请求的实体,而RequestBody
和ResponseBody
则是内部的数据体
请求
package com.example.demo.beans;
/**
* 请求实体
* @author 程序员潇然 https://crazybytex.com/
*/
public class RequestBean <RQ>{
//还可以保存一些通用请求参数
private RQ data;
public RQ getData() {
return data;
}
public void setData(RQ data) {
this.data = data;
}
}
请求体
package com.example.demo.beans;
/** 请求体
* @author 程序员潇然 https://crazybytex.com/
*/
public class RequestBody {
}
响应
package com.example.demo.beans;
/**
* 响应实体
* @author 程序员潇然 https://crazybytex.com/
*/
public class ResponseBean<RS> {
private Integer code;
private String msg;
private RS data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public RS getData() {
return data;
}
public void setData(RS data) {
this.data = data;
}
@Override
public String toString() {
return "ResponseBean{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
响应体
package com.example.demo.beans;
/**
* 响应体
*
* @author 程序员潇然 https://crazybytex.com/
*/
public class ResponseBody {
}
通用处理器
package com.example.demo;
import com.alibaba.fastjson2.JSON;
import com.example.demo.beans.RequestBean;
import com.example.demo.beans.RequestBody;
import com.example.demo.beans.ResponseBean;
import com.example.demo.beans.ResponseBody;
import com.example.demo.sample.TestListType;
import com.example.demo.sample.TestResponse;
import com.example.demo.sample.TestqRequest;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* 通用的执行器 样例,比如可以设计为模板模式
* 抽象一些通用处理逻辑,子类负责具体的某些请求响应的实现 并且通过子类指定请求与响应的泛型
* 比如通用的封装的发起http请求 通用的rpc调用处理等
*
* @param <RQ>
* @param <RS>
* @author 程序员潇然 https:crazybytex.com
*/
public class HttpExecutor<RQ, RS> {
public ResponseBean<RS> doPost(RequestBean<RQ> requestBean) {
//此处假设为执行某些逻辑处理、调用之后,获取到的响应结果,结果是json的
String resultJson1 = "{\n" +
" \"code\": 45,\n" +
" \"msg\": \"laboris eu irure voluptate\"\n" +
"}";
String resultJson2 = "{\"code\":1,\"data\":{\"a\":1,\"b\":5,\"x\":\"feffewef\"},\"msg\":\"成功\"}";
String resultJson3 = "{\n" +
" \"code\": 1,\n" +
" \"msg\": \"识别成功\",\n" +
" \"data\": [\n" +
" {\n" +
" \"classId\": 1,\n" +
" \"x1\": 0,\n" +
" \"y1\": 0,\n" +
" \"x2\": 200,\n" +
" \"y2\": 200\n" +
" },\n" +
" {\n" +
" \"classId\": 2,\n" +
" \"x1\": 5,\n" +
" \"y1\": 10,\n" +
" \"x2\": 36,\n" +
" \"y2\": 21\n" +
" },\n" +
" {\n" +
" \"classId\": 3,\n" +
" \"x1\": 44,\n" +
" \"y1\": 55,\n" +
" \"x2\": 66,\n" +
" \"y2\": 77\n" +
" },\n" +
" {\n" +
" \"classId\": 4,\n" +
" \"x1\": 24,\n" +
" \"y1\": 22,\n" +
" \"x2\": 58,\n" +
" \"y2\": 96\n" +
" }\n" +
" ]\n" +
"}";
String resultJson = resultJson3;
/******************************************************************************************************************/
ResponseBean<RS> responseBean = (ResponseBean<RS>) JSON.parseObject(resultJson, ResponseBean.class);
Map<String, Object> map = JSON.parseObject(resultJson, Map.class);
if (map.get("data") != null) {
//请求参数
Type requestParameterizedType = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
//响应参数
Type responseParameterizedType = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[1];
responseBean.setData(JSON.parseObject(JSON.toJSONString(map.get("data")), responseParameterizedType));
}
return responseBean;
}
public static void main(String[] args) {
/*
注意,下面是简化形式的子类创建,匿名类,注意new 后面有一个{}
这样就可以指定 请求以及响应类型
*/
// RequestBean<RequestBody> requestBean1 = new RequestBean<>();
// ResponseBean<ResponseBody> responseBean1 = new HttpExecutor<RequestBody, ResponseBody>() {
// }.doPost(requestBean1);
// System.out.println(responseBean1);
// RequestBean<RequestBody> requestBean2 = new RequestBean<>();
// ResponseBean<TestResponse> responseBean2 = new HttpExecutor<RequestBody, TestResponse>() {
// }.doPost(requestBean2);
// System.out.println(responseBean2);
//
RequestBean<RequestBody> requestBean3 = new RequestBean<>();
ResponseBean<List<TestListType>> responseBean3 = new HttpExecutor<RequestBody, List<TestListType>>() {
}.doPost(requestBean3);
System.out.println(responseBean3);
}
}
通过:
调整String resultJson = resultJson3;
这行代码控制测试数据
main
方法中放开对应的序号请求
可以进行测试查看结果。
完整结构如下:
样例bean
package com.example.demo.sample;
import com.example.demo.beans.ResponseBody;
public class TestResponse extends ResponseBody {
private Integer a;
private Integer b;
private String x;
public Integer getA() {
return a;
}
public void setA(Integer a) {
this.a = a;
}
public Integer getB() {
return b;
}
public void setB(Integer b) {
this.b = b;
}
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
@Override
public String toString() {
return "TestResponse{" +
"a=" + a +
", b=" + b +
", x='" + x + '\'' +
'}';
}
}
package com.crazybytex.hello.fastjson.sample;
public class TestListType {
private Integer classId;
private Integer x1;
private Integer y1;
private Integer x2;
private Integer y2;
public Integer getClassId() {
return classId;
}
public void setClassId(Integer classId) {
this.classId = classId;
}
public Integer getX1() {
return x1;
}
public void setX1(Integer x1) {
this.x1 = x1;
}
public Integer getY1() {
return y1;
}
public void setY1(Integer y1) {
this.y1 = y1;
}
public Integer getX2() {
return x2;
}
public void setX2(Integer x2) {
this.x2 = x2;
}
public Integer getY2() {
return y2;
}
public void setY2(Integer y2) {
this.y2 = y2;
}
@Override
public String toString() {
return "TestListType{" +
"classId=" + classId +
", x1=" + x1 +
", y1=" + y1 +
", x2=" + x2 +
", y2=" + y2 +
'}';
}
}
代码位于gitee上的代码测试库中:
https://gitee.com/crazybytex/java-code-fragment/tree/master/src/main/java/com/crazybytex/fragment/fastjson
FastJson 解析的类型
通常对于对象的解析大概就是这种形式
JSON.parseObject(resultJson, Map.class);
这种就是字符串,类型
static <T> T parseObject(String text, Class<T> clazz) {
除了Class,另外还有:
static <T> T parseObject(String text, Type type) {
这个Type
package java.lang.reflect;
/**
* Type is the common superinterface for all types in the Java
* programming language. These include raw types, parameterized types,
* array types, type variables and primitive types.
*
* @since 1.5
*/
public interface Type {
/**
* Returns a string describing this type, including information
* about any type parameters.
*
* @implSpec The default implementation calls {@code toString}.
*
* @return a string describing this type
* @since 1.8
*/
default String getTypeName() {
return toString();
}
}
使用泛型的话,经常是需要接触到这个类的,因为有了类型才能解析。
而Class其实也是他的子类型
所以想要了解清楚Json的解析,就需要对这块进行研究。
另外,还有一种解析形式,针对集合泛型的
static <T> T parseObject(String text, TypeReference typeReference, JSONReader.Feature ... features) {
使用形式如:
JSON.parseObject(JSON.toJSONString(map.get("data")), new TypeReference<List<Response>>() {
})
需要注意到的是这是一个抽象类,所以使用的是匿名类
public abstract class TypeReference<T>
转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-89-1-1.html