1. 前言

  1. 在工作中,必然少不了JSON转化对象,而一般来说JSON的转化,要么就是在controller层,springboot帮忙转化好了,要么就是很简单的常转List、Map等等。

  2. 而在学习Feign的时候,可以 自定义Decoder解析器 ,对返回报文做个性化处理,但这个时候,对方返回的数据就需要自己 将json字符串转为对应的对象 了。

  3. 而在自己转化的时候,发现ObjectMapper提供如下两个方法:
    在这里插入图片描述

    一个是class类型的参数,一个是JavaType类型的参数,而该decode方法中,只有Type类型。

  4. 这个时候不经会发问几个问题:

    1. 如何将feign请求到的返回数据转为对象呢?
    2. Type类型是什么东西,在decoder方法中要怎么转化呢?
    3. 如果可以转化了,那复杂的对象又要如何书写代码呢?
  5. 上述问题是在我学习feign自定义解析器解析返回报文时候出现的, 如何自定义解析一个复杂的报文

  6. 从而衍生出: ObjectMapper转化对象方法到底有哪些?

2. 先说结论

  1. 通常 转对象 使用方式是 objectMapper.readValue(String jsonStr, Class<T> clazz);
  2. 转List、Map 使用方式是 objectMapper.readValue(String jsonStr, TypeReference<T> valueTypeRef); 例子如下:
    List: objectMapper.readValue(json, new TypeReference<List<JsonPerson>>() {});
    Map: objectMapper.readValue(json, new TypeReference<Map<String, JsonPerson>>() {});
  3. 使用constructType方式 转化对象 ,就是 提前把需要转成的对象的类型先构造出来 ,之后就交给objectMapper直接反序列化即可。
  4. 常用 创建类型 的方法:
    1. objectMapper.constructType() 直接创建对应的类型出来,如 创建单对象的类型 objectMapper.constructType(T.class)
    2. objectMapper.getTypeFactory().constructParametricType() 创建带有参数化的类型 ,如转List: objectMapper.getTypeFactory().constructParametricType(List.class, T.class).

3. 快速入门

  1. 准备实体类如下:
        @Getter
        @ToString
        static class JsonPerson {
            private String name;
            private String pwd;
    

    1. 常用转对象、List、Map(复习常用的方式)

    1. 对象,直接指明对象的class类

          private static void json(ObjectMapper objectMapper) throws JsonProcessingException {
              String json = "{\n" +
                      "        \"name\":\"test-name\",\n" +
                      "        \"pwd\":\"test-pwd\"\n" +
                      "    }";
              final JsonPerson jsonPerson = objectMapper.readValue(json, JsonPerson.class);
              System.out.println(jsonPerson);
      

      在这里插入图片描述

    2. List
      一种直接指明ArrayList的class类

      	// 指明ArrayList的class类的方式
          private static void json2(ObjectMapper objectMapper) throws JsonProcessingException {
              String json2 = "[{\n" +
                      "        \"name\":\"test-name\",\n" +
                      "        \"pwd\":\"test-pwd\"\n" +
                      "    }]";
              final List<JsonPerson> jsonPersonList2 = objectMapper.readValue(json2, ArrayList.class);
              System.out.println(jsonPersonList2);
      

      在这里插入图片描述
      在这里插入图片描述
      另一种使用TypeReference(一般都是用这种)

          private static void json3(ObjectMapper objectMapper) throws JsonProcessingException {
              String json3 = "[{\n" +
                      "        \"name\":\"test-name\",\n" +
                      "        \"pwd\":\"test-pwd\"\n" +
                      "    }]";
              final List<JsonPerson> jsonPersonList = objectMapper.readValue(json3, new TypeReference<List<JsonPerson>>() {});
              System.out.println(jsonPersonList);
      

      在这里插入图片描述

    3. Map跟List同理,有两种方式
      一种直接指明Map的class类

          private static void json4(ObjectMapper objectMapper) throws JsonProcessingException {
              String json4 = "{\n" +
                      "    \"TestData1\": {\n" +
                      "        \"name\": \"test-name\",\n" +
                      "        \"pwd\": \"test-pwd\"\n" +
                      "    },\n" +
                      "    \"TestData2\": {\n" +
                      "        \"name\": \"test-name2\",\n" +
                      "        \"pwd\": \"test-pwd2\"\n" +
                      "    }\n" +
                      "}";
              final Map<String, JsonPerson> jsonPersonMap = objectMapper.readValue(json4, Map.class);
              System.out.println(jsonPersonMap);
      

      在这里插入图片描述
      在这里插入图片描述
      另一种使用TypeReference(一般都是用这种)

      private static void json5(ObjectMapper objectMapper) throws JsonProcessingException {
              String json5 = "{\n" +
                      "    \"TestData1\": {\n" +
                      "        \"name\": \"test-name\",\n" +
                      "        \"pwd\": \"test-pwd\"\n" +
                      "    },\n" +
                      "    \"TestData2\": {\n" +
                      "        \"name\": \"test-name2\",\n" +
                      "        \"pwd\": \"test-pwd2\"\n" +
                      "    }\n" +
                      "}";
              final Map<String, JsonPerson> jsonPersonMap = objectMapper.readValue(json5, new TypeReference<Map<String, JsonPerson>>() {
              });
              System.out.println(jsonPersonMap);
      

      2. 使用constructType方式

      1. constructType方式:根据输入的参数先构建出需要转化的java类型

      2. 直接看例子:
        先看普通的对象

            private static void json6(ObjectMapper objectMapper) throws JsonProcessingException {
                String json6 = "{\n" +
                        "        \"name\":\"test-name\",\n" +
                        "        \"pwd\":\"test-pwd\"\n" +
                        "    }";
                // 构建JsonPerson类型的转化对象
                final JavaType javaType = objectMapper.constructType(JsonPerson.class);
                // 告诉objectMapper:json6字符串需要转为 javaType的类型,即就是JsonPerson类
                final JsonPerson jsonPerson = objectMapper.readValue(json6, javaType);
                System.out.println(jsonPerson);
        

        在这里插入图片描述

      3. 有人就会说,这很弱鸡呀,还不如直接objectMapper.readValue(json, class),别着急,上述是转简单对象的操作而已,这只是先让大家初步认识constructType

      4. 先看例子中objectMapper.constructType(JsonPerson.class);这个方法源码:

            public JavaType constructType(Type t) {
            	// 先校验非空
                _assertNotNull("t", t);
                // 使用类型工厂 创建t类型的类型
                return _typeFactory.constructType(t);
        
      5. 此时产生第一个问题:Type类是什么,如果没上述例子,第一次看见这个方法,我们怎么知道要传入什么参数呢

      6. 需要补充一下其他知识点,Type是什么

        1. Type是Java 编程语言中所有类型的公共高级接口。
        2. 简单来说:所有的数据类型的类型都是Type, Class也是继承自Type的,再通俗来说,Type就是所有数据类型的“爹”。
        3. Type的直接子接口(也就是Type具体有哪些类型):
          1.ParameterizedType: 表示一种参数化的类型,比如Collection,即普通的泛型。
          2.TypeVariable:是各种类型变量的公共父接口,就是泛型里面的类似T、E。
          3.GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型,比如List<>[],T[]这种。
          4.WildcardType:代表一种通配符类型表达式,类似? super T这样的通配符表达式。
        4. 下面是找到比较好并且参考的资料, 大家看看他们写的代码例子,应该可以理解这高深的话语了
          1. 对java-Type的理解
          2. java中的Type
          3. TYPE JAVA类型
      7. 看完第六大点,就可以解决第五大点的问题,如果还不能理解,就通俗到把Type就认为是类型constructType就是理解为构造要转化什么java类型

      8. 接下来我们看第二个例子:转List对象

            private static void json7(ObjectMapper objectMapper) throws JsonProcessingException {
                String json7 = "[{\n" +
                        "        \"name\":\"test-name\",\n" +
                        "        \"pwd\":\"test-pwd\"\n" +
                        "    }]";
                // 获取Type的工厂
                final TypeFactory typeFactory = objectMapper.getTypeFactory();
                // 创建 JsonPerson的Type类型
                final JavaType jsonPersonType = typeFactory.constructType(JsonPerson.class);
                // 因为转化的是List<JsonPerson>类型
                // 则也就是要创建有参数的Type类型 
                // 即 constructParametricType(List.class, jsonPersonType)---> List<JsonPerson>
                final JavaType javaType = typeFactory.constructParametricType(List.class, jsonPersonType);
                // 反序列化
                final List<JsonPerson> jsonPersonList = objectMapper.readValue(json7, javaType);
                // 得到结果集
                System.out.println(jsonPersonList);
        

        在这里插入图片描述
        若上述的注释可以看的懂,其实也可以用下面简单方式(已有api):

            private static void json8(ObjectMapper objectMapper) throws JsonProcessingException {
                String json8 = "[{\n" +
                        "        \"name\":\"test-name\",\n" +
                        "        \"pwd\":\"test-pwd\"\n" +
                        "    }]";
                // 获取Type的工厂
                final TypeFactory typeFactory = objectMapper.getTypeFactory();
                // 因为转化的是List<JsonPerson>类型
                // 直接API constructCollectionType 创建集合类型
                // 得到Collection<T>类型
                final JavaType javaType = typeFactory.constructCollectionType(List.class, JsonPerson.class);
                // 反序列化
                final List<JsonPerson> jsonPersonList = objectMapper.readValue(json8, javaType);
                // 得到结果集
                System.out.println(jsonPersonList);
        

        在这里插入图片描述

      9. 接下来第三个例子:转Map<String, JsonPerson>类型,其实也是大同小异,也是两种方式,细节如下:

        private static void json9(ObjectMapper objectMapper) throws JsonProcessingException {
                String json9 = "{\n" +
                        "    \"TestData1\": {\n" +
                        "        \"name\": \"test-name\",\n" +
                        "        \"pwd\": \"test-pwd\"\n" +
                        "    },\n" +
                        "    \"TestData2\": {\n" +
                        "        \"name\": \"test-name2\",\n" +
                        "        \"pwd\": \"test-pwd2\"\n" +
                        "    }\n" +
                        "}";
                // 获取Type的工厂
                final TypeFactory typeFactory = objectMapper.getTypeFactory();
                // 因为转化的是Map<String, JsonPerson>类型
                // 主类型是Map.class 然后就是key value的类型:String.class JsonPerson.class
                final JavaType javaType = typeFactory.constructParametricType(Map.class, String.class, JsonPerson.class);
                // 也可以使用这种方式
                // final JavaType javaType = typeFactory.constructMapType(Map.class, String.class, JsonPerson.class);
                // 反序列化
                final Map<String,JsonPerson> jsonPersonMap = objectMapper.readValue(json9, javaType);
                // 得到结果集
                System.out.println(jsonPersonMap);
        

        在这里插入图片描述

      10. 为了节约时间,我们将直接给个高级的例子:转为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);
        

        4. 其他

        1. 对于怎么实现Feign的自定义Decoder解析器,等写到Feign知识点的时候再说吧,提前剧透一下,Feign真的很有意思
        在工作中,必然少不了JSON转化对象,而一般来说JSON的转化,要么就是在controller层,springboot帮忙转化好了,要么就是简单的常转List、Map等。而在学习Feign时,可以自定义Decoder解析器,对返回报文做个性化处理,但此时对方返回的数据就需要自己将json字符串转为对应的对象了。而在自己转化的时候,发现ObjectMapper提供如下两个方法:一个是class类型的参数,一个是JavaType类型的参数,而该decode方法中,只有Type类型,那到底应该如何操作呢,请看本文 https://www.cnblogs.com/whyblogs/p/15062486.html Jackson,我感觉是在JavaJson之间相互换的最快速的框架,当然Google的Gson也很不错,但是参照网上有人的性能测试,看起来还是Jackson比较快一点 Jackson处理一般的JavaBean和Json之间的换只要使用ObjectMapper 对象的readValue和writeValueAsString两个方法就能实现。但是如果要换复杂类型Collection如 List,那么 // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) package com.fasterxml.jackson.databind; import com.fasterxml.jackson.annotation.Pr...
        要使用ObjectMapper对象换为List类型的对象,可以使用以下方法: 1. 使用readValue方法TypeReference类:objectMapper.readValue(json, new TypeReference<List<YourClass>>() {}); 2. 使用convertValue方法List<YourClass> yourList = objectMapper.convertValue(yourObject, new TypeReference<List<YourClass>>() {}); 3. 使用constructType方法objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(List.class, YourClass.class)); 请根据你的具体需求选择适合的方法对象List类型的对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
        设计第三方jar包中有bean对象时,要如何自动加载到被引用的应用中(EnableAutoConfiguration、BeanDefinitionRegistryPostProcessor使用) 先回复你的问题:目前我的知识水平是使用了方法二的方式解决的。感谢你认真读我的文章,并且思考很认真,这个问题提的很好,这个 @Configuration里面的@Bean不生效的问题,遇到真的就头大,我很久之前发现也写了另一个博客:https://blog.csdn.net/xueyijin/article/details/129899228 设计第三方jar包中有bean对象时,要如何自动加载到被引用的应用中(EnableAutoConfiguration、BeanDefinitionRegistryPostProcessor使用) xtwoy: 您好 我按照文章的第三方式 ,其中有个使用注解 @Configuration 配置对象,对象已经注册到容器中,但在这个对象里面 使用@Bean注册不了。再不使用方法二的情况下,如解决呢?谢谢!!