程序员潇然 发表于 2022-7-22 15:12:30

[fastjson2]解析 通用泛型框架工具类解析 List获取泛型

Json是开发过程中饶过不去的一种格式,而且这种格式非常的通用。

而FastJson2 是一种使用广泛的解析工具,对于一些工具、框架性质的类,又经常不可避免的需要使用到Java的泛型,本文就简单记录下泛型场景下,JSON的数据处理解析。

主要解决Fastjson解析泛型,嵌套类型等。

### 常用的交互模型

先介绍下一般常用的交互格式(请求响应类似的道理,以响应举例):

一种非常常见的格式化模板代码为:

```java
public class ResponseBean<RS> {
    private Integer code;
    private String msg;
    private RS data;

}
```

对应的Json串的形式如下,其中data节点也可能没有,也可能嵌套多层:

```json
{
"code":1,
"msg":"成功",
"data": {
       ...........
}
}
```

### 响应返回的分类

(1)最基础格式,没有嵌套,单纯地字段与对应的值,返回请求与响应,也可能包含更多的一些其他字段

```json
{
"code": 1,
"msg": "成功"
}
```

(2)稍微复杂点,对象层次的嵌套,不涉及到`List<>`也就是没有数组。

从类设计的视角看,包含了一个对象,这个对象包含两个属性

```json
{
"code":1,
"msg":"成功",
"data": {
    "position": 1,
    "show": true
}
}
```

(3)返回字段与`List<>`,并且通常使用`data`作为对象的key,也就是返回码、返回消息单独字段,数据体包含在data中,并且

```json
{
"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` 则是内部的数据体

!(data/attachment/forum/202207/22/153049uo78zu44u74ev8c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

#### 请求

```java
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;
    }
}
```

#### 请求体

```java
package com.example.demo.beans;

/** 请求体
* @author 程序员潇然 https://crazybytex.com/
*/
public class RequestBody {
}
```

### 响应

```java
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 +
                '}';
    }
}
```

#### 响应体

```java
package com.example.demo.beans;

/**
* 响应体
*
* @author 程序员潇然 https://crazybytex.com/
*/
public class ResponseBody {

}
```

### 通用处理器

```java
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();

            //响应参数
            Type responseParameterizedType = ((ParameterizedType) getClass().getGenericSuperclass())
                  .getActualTypeArguments();
            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` 方法中放开对应的序号请求

可以进行测试查看结果。

完整结构如下:

!(data/attachment/forum/202207/22/160857w92l0q9q8ddvzqh5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

### 样例bean

```java
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 + '\'' +
                '}';
    }
}
```

```java
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);
````

这种就是字符串,类型

```java
static <T> T parseObject(String text, Class<T> clazz) {
```

除了Class,另外还有:

```java
static <T> T parseObject(String text, Type type) {
```

这个Type

```java
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其实也是他的子类型
!(data/attachment/forum/202207/22/170504wqte8g8nqz6qg7q4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

所以想要了解清楚Json的解析,就需要对这块进行研究。

另外,还有一种解析形式,针对集合泛型的

```
static <T> T parseObject(String text, TypeReference typeReference, JSONReader.Feature ... features) {
```

使用形式如:

```java
JSON.parseObject(JSON.toJSONString(map.get("data")), new TypeReference<List<Response>>() {
                  })
```

需要注意到的是这是一个抽象类,所以使用的是匿名类

```java
public abstract class TypeReference<T>
```



!(data/attachment/forum/202206/16/141330jha7st9soow8772i.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "common_log.png")
`转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-89-1-1.html `

页: [1]
查看完整版本: [fastjson2]解析 通用泛型框架工具类解析 List获取泛型