当前位置: 首页 > article >正文

Jaskson处理复杂的泛型对象

参考链接:ObjectMapper转化对象常用方法(转LIst、Map,以及Type、JavaType、constructType的学习)

文章目录

    • 开篇
    • 范例1:List<Map<String, Person>>
    • 范例2:Map<String, List\<Person>>
    • 范例3:JsonResponse<Map\<String,List\<JsonPerson\>>>
    • 结语

开篇

Jackson是一个在Java体系中被广泛使用的Json序列化和反序列化类库,它提供了丰富的API给开发者使用。

@Data
public class DataInfo<T> {
   
    private Integer type;

    private T data;

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        DataInfo<Car> dataInfo = new DataInfo<>();
        dataInfo.setType(1);
        dataInfo.setData(new Car("奔驰01", "奔驰", "黑色"));

        String str1 = mapper.writeValueAsString(dataInfo);
        System.out.println(str1);

        DataInfo dataInfo1 = mapper.readValue(str1, DataInfo.class);
        System.out.println(dataInfo1); // 默认是LinkedHashMap类型

        DataInfo<Car> dataInfo2 = mapper.readValue(str1, new TypeReference<DataInfo<Car>>() {});
        System.out.println(dataInfo2); // 正确的泛型 DataInfo<Car>, 缺点是不能将Car.class作为参数

        JavaType javaType = mapper.getTypeFactory().constructParametricType(DataInfo.class, Car.class);
        DataInfo dataInfo3 = mapper.readValue(str1, javaType);
        System.out.println(dataInfo3); // 正确的泛型 DataInfo<Car>, 能将Car.class作为参数

		JavaType carJavaType = mapper.getTypeFactory().constructType(Car.class);
        JavaType dataInfoCarJavaType = mapper.getTypeFactory().constructParametricType(DataInfo.class, carJavaType);
        DataInfo dataInfo4 = mapper.readValue(str1, dataInfoCarJavaType);
        System.out.println(dataInfo4); // 正确的泛型 DataInfo<Car>, 能将Car.class作为参数
    }

}

今天记录下最近利用Jackson处理复杂的泛型对象的心得,其核心就是利用TypeFactory.constructParametricType()方法,从内到外依此构造Type。

范例1:List<Map<String, Person>>
范例2:Map<String, List<Person>>

范例1:List<Map<String, Person>>

假设我有一个对象List<Map<String, Person>>,我先构造对象然后转为字符串。

//init
List<Map<String, Person>> result = new ArrayList<>();
Map<String, Person> map = new HashMap<>();
map.put("lcf", new Person("lcf"));

Map<String, Person> map2 = new HashMap<>();
map2.put("hh", new Person("hh"));
result.add(map);
result.add(map2);

//toStr
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(result);

然后将其反序列化:

//toObj JsonMappingException,json转化异常
Map map1 = mapper.readValue(s, Map.class);

直接这样转换是会报错的!

需要利用 TypeFactory.constructParametricType()进行JavaType的类型构造:List<Map<String, Person>>

需要注意的是,在构造的时候需要从内到外进行构造:

  1. 先构造Map<String,Person>得到innerType
  2. 再构造List<innerType>

代码如下所示:

//先构造Map<String,Person>得到innerType,第一个参数为外层对象HashMap,第二个参数为String,第三个参数为Person
JavaType innerType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, Person.class);
//再构造List<innerType> 
JavaType resultType = mapper.getTypeFactory().constructParametricType(ArrayList.class, innerType);
//反序列化
List<Map<String, Person>> result2 = mapper.readValue(s, resultType);

范例2:Map<String, List<Person>>

//构造  Map<String, List<Person>>
//1.先构造右边部分
JavaType rightType = mapper.getTypeFactory().constructParametricType(ArrayList.class, Person.class);
//2. 再构造全局
JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, rightType.getRawClass());
Map<String, List<Person>> o = mapper.readValue(str, javaType);

这里有一个小知识点,注意的是参数类型要匹配:constructParametricType 方法有如下2种声明需要注意:

public JavaType constructParametricType(Class<?> parametrized, Class<?>... parameterClasses) 
public JavaType constructParametricType(Class<?> rawType, JavaType... parameterTypes)

方法中后面的可变形参参数必须一致。
可以查看返利2的 再构造全局,我本来是希望:

JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, rightType);

但是IDE提示参数不匹配,认真一查看确实是:一个是Class,一个是JavaType。
所以通过直接getRawClass解决该问题:

//构造  Map<String, List<Person>>
JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, rightType.getRawClass());

范例3:JsonResponse<Map<String,List<JsonPerson>>>

// 为什么需要这一层呢?
// 1\. 接口的返回值将会封装为下述结构体,当调用方接受到报文的时候,可以直接优先判断code即返回码,可快速知道这次请求到底是成功还是失败
// 若失败,则直接读取错误信息message,若成功,直接读取data数据。
// 2\. 也是给会报错的代码打个标志,若出错误了,可以快速根据code返回码,判断对应代码是那段出问题,快速定位。
  @Getter
  @ToString
  static class JsonResponse<T> {
      private String code;
      private String message;
      private T data;
  }

  @Getter
  @ToString
  static class JsonPerson {
      private String name;
      private String pwd;
  }

private static void json11(ObjectMapper objectMapper) throws JsonProcessingException {
      String json11 = "{\n" +
              "    \"code\": \"success\",\n" +
              "    \"data\": {\n" +
              "        \"TestData1\": [\n" +
              "            {\n" +
              "                \"name\": \"test-data-name-one\",\n" +
              "                \"pwd\": \"test-data-pwd-one\"\n" +
              "            },\n" +
              "            {\n" +
              "                \"name\": \"test-data-name-two\",\n" +
              "                \"pwd\": \"test-data-pwd-two\"\n" +
              "            }\n" +
              "        ],\n" +
              "        \"TestData2\": [\n" +
              "            {\n" +
              "                \"name\": \"test-data2-name-one\",\n" +
              "                \"pwd\": \"test-data2-pwd-one\"\n" +
              "            },\n" +
              "            {\n" +
              "                \"name\": \"test-data2-name-two\",\n" +
              "                \"pwd\": \"test-data2-pwd-two\"\n" +
              "            }\n" +
              "        ]\n" +
              "    }\n" +
              "}";

      // 获取Type的工厂
      final TypeFactory typeFactory = objectMapper.getTypeFactory();

      // 因为转化的是JsonResponse<Map<String,List<JsonPerson>>> 类型 由里到外,一层层创建对应类型
      // 先创建List<JsonPerson> 类型
      final JavaType listJsonPersonType = typeFactory.constructCollectionType(List.class, JsonPerson.class);

      // 由于 constructMapType方法有如下两种:
      //  1\. constructMapType(Class<? extends Map> mapClass,Class<?> keyClass, Class<?> valueClass)
      //  2\. constructMapType(Class<? extends Map> mapClass, JavaType keyType, JavaType valueType)

      // 对应的key value入参,要不都是class,要不都是JavaType 类型
      // 因此需要把Map中的String先创建 JavaType 类型
      final JavaType stringType = typeFactory.constructType(String.class);

      // 再创建Map<String,List<JsonPerson>> 类型
      final JavaType mapType = typeFactory.constructMapType(Map.class, stringType, listJsonPersonType);

      // 再创建JsonResponse<Map<String,List<JsonPerson>>> 类型
      final JavaType lastType = typeFactory.constructParametricType(JsonResponse.class, mapType);

      // 反序列化
      final JsonResponse<Map<String,List<JsonPerson>>> jsonResponse = objectMapper.readValue(json11, lastType);
      // 得到结果
      System.out.println(jsonResponse);
  }

结语

核心思路:从内到外构造类型,一步一步来!


http://www.kler.cn/a/400432.html

相关文章:

  • Ubuntu 22.04 上快速搭建 Samba 文件共享服务器
  • 优化C++设计模式:用模板代替虚函数与多态机制
  • 跨平台WPF框架Avalonia教程 一
  • Ubuntu22.04基于ROS2-Humble安装moveit2教程(亲测)
  • 《Spring 基础之 IoC 与 DI 入门指南》
  • Python中的正则表达式教程
  • (Linux 入门) 基本指令、基本权限
  • 动态规划 之 子序列系列 算法专题
  • 脚手架vue-cli,webpack模板
  • 资源管理功能拆解——如何高效配置和管理项目资源?
  • 高斯数据库Postgresql死锁和锁表解决方法
  • MATLAB深度学习(三)——LeNet卷积神经网络
  • 独立站干货:WordPress主机推荐
  • Python高级编程模式和设计模式
  • CTF攻防世界小白刷题自学笔记14
  • Flink算子
  • Vue 3 中 ref 属性详解:操作 DOM 元素的利器
  • Python的3D可视化库 - vedo (1)简介和模块功能概览
  • ThinkPHP6的ORM模型
  • hive-内部表外部表-详细介绍
  • Java 网络编程:Socket 与网络通信
  • Jtti:服务器总是自动重启怎么办?
  • 如何保存python文件
  • 最新6.7分非肿瘤纯生信,使用机器学习筛选慢阻肺中的关键基因。机器学习在非肿瘤生信文章中正火,可重复!
  • Python自动化DevOps任务入门
  • stm32学习笔记----51单片机和stm32单片机的区别