• Spring Boot 2.x系列【17】功能篇之JSON


    有道无术,术尚可求,有术无道,止于术。

    本系列Spring Boot版本2.7.0

    什么是JSON

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,可以在多种语言之间进行数据交换,同时也易于机器解析和生成。

    JSON 是在2001 年开始推广使用的数据格式,在2005年-2006年正式成为主流的数据格式,雅虎和谷歌就在那时候开始广泛地使用JSON格式。

    JSON 是一种取代XML的数据结构,和XML相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度。

    JSON其实也就是字符串, 只不过元素会使用特定的符号标注。

    比如

    {"a": 1, "b": [1, 2, 3]}
    
    • 1

    在案例中

    • {} 双括号表示对象

    • [] 中括号表示数组

    • ""双引号内是属性或值

    • : 冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)

    目前JSON已经是公认的、服务器与Web应用之间数据传输的API标准。

    常用JSON 库

    Gson

    项目地址

    Gson是由Google公司开发的一个开源Java 类库

    特点

    • 易于使用 :Gson API提供了一个高级外观来简化常用的用例。
    • 无需创建映射 :Gson API为大部分要序列化的对象提供了默认映射。
    • 性能优 :Gson速度相当快,内存占用量低。 它适用于大型对象图或系统。
    • 干净JSON: Gson创建一个干净而紧凑的JSON结果,它易于阅读。
    • 无依赖性:Gson库不需要JDK以外的任何其他库。
    • 开源 : Gson库是开源的; 它是免费提供的。

    FastJson

    Fastjson是一个Java语言编写的高性能的JSON库,由阿里巴巴公司开发,号称其独创的算法解析速度超过所有json库。

    其核心开发人员是江湖中赫赫有名的温少,大佬还开发了大名鼎鼎的Druid数据库连接池。
    在这里插入图片描述
    目前使用最多的是1.x 版本,但是目前该版本好像只处于维护阶段了。

    2022 年 4月份,Fastjson 发布了重构的2.X 版本,重点优化之前版本存在的诸多问题,

    Jackson

    项目地址

    Jackson 也是一个 Java 的用来处理 JSON 格式数据的类库,依托于Spring 生态,和其自身优越的性能,目前应该算是最受欢迎的JSON 框架。

    Spring MVC Spring Boot都是使用Jackson 作为默认的 JSON 库。

    接下来我们熟悉下Jackson 中比较重要的几个组件:

    1、ConfigFeature

    ConfigFeature从字面上看是配置特性的意思,在对象和JSON之间进行序列化或反序列化时,肯定是需要配置策略的,比如时间转换的格式,而这个接口就是这个作用。

    此接口一共有三个实现类(枚举)︰

    • MapperFeature : ObjectMapper/JsonMapper特征
    • SerializationFeature :序列化特征
    • DeserializationFeature:反序列化特征

    SerializationFeature就是序列化时,将对象转为JSON 字符串的特征配置,可配置项如下:

        // jackson在序列化时,可以在json外面再包裹一层,官方叫做WRAP_ROOT_VALUE,通常叫做root对象
        // 是否支持root对象,开启后@JsonRootName注解才会生效,一般没啥用
        WRAP_ROOT_VALUE(false),
    
        // 是否缩进输出,也就是格式化输出,和SQL 一样,换行输出
        INDENT_OUTPUT(false),
    
        // 没有Getter方法,属性为私有,也就是没有访问器时,是否抛出异常,设置为false时,输出 {}
        FAIL_ON_EMPTY_BEANS(true),
    
        // 自我引用时,是否报错
        FAIL_ON_SELF_REFERENCES(true),
    
        // 是否需要捕获异常然后重新抛出
        WRAP_EXCEPTIONS(true),
    
        // 当展开的对象有类型信息时会抛出错误。禁用时,对象将被解包并丢弃类型信息。
        FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS(true),
    
        // 如果出现自身引用自身的情况,则把成员对象变成null
        WRITE_SELF_REFERENCES_AS_NULL(false),
    
        // 当进行writevalue写时,是否自动帮你关闭实现了closeable的流
        CLOSE_CLOSEABLE(false),
    
        // WRITE写之后,是否自动FLUSH
        FLUSH_AFTER_WRITE_VALUE(true),
    
        // 日志类型是否按照TIMESTAMP格式输出
        WRITE_DATES_AS_TIMESTAMPS(true),
    
        // 时间类型的KEY是否按照TIMESTAMP格式输出
        WRITE_DATE_KEYS_AS_TIMESTAMPS(false),
    
        // 时区序列化为 +08:00 形式
        WRITE_DATES_WITH_ZONE_ID(false),
    
        // 是否使用分区日期时间值中的 timezoneoffset 的功能
        WRITE_DATES_WITH_CONTEXT_TIME_ZONE(true),
    
        // 确定表示时间段(durations, periods, ranges)的时间值是否默认使用数字或文本表示进行序列化的功能
        WRITE_DURATIONS_AS_TIMESTAMPS(true),
    
        // 是否把char[]数组也当做数组序列化
        WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS(false),
    
        // 序列化枚举是否使用tostring ()方法。默认是name()方法
        WRITE_ENUMS_USING_TO_STRING(false),
    
        // 序列化枚举是否使用数字序列
        WRITE_ENUMS_USING_INDEX(false),
    
        //  序列化枚举类型的KEY 是否使用数字序列
        WRITE_ENUM_KEYS_USING_INDEX(false),
    
        // 是否序列化MAP 类型中的NULL 值
        // 2.9标为过时。使用(@JsonInclude注解或者ObjectNapper#configOverride(Class}来改变
        @Deprecated
        WRITE_NULL_MAP_VALUES(true),
    
        // 2.8标为过时。使用@]sonInclude注解代替
        @Deprecated
        WRITE_EMPTY_JSON_ARRAYS(true),
    
        // 序列化单元素数组时不以数组来输出
        WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED(false),
    
        // 2.5标为过时。使用JsonGenerator.Feature#wRITE_BIGDECIMAL_AS_PLAIN代替
        //  是否使用 {@link java.math.BigDecimal#toPlainString()} 序列化  {@link java.math.BigDecimal}
        @Deprecated
        WRITE_BIGDECIMAL_AS_PLAIN(false),
    
        // 将日期时间戳写为纳秒
        WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS(true),
    
        // 是否根据Map的key帮你排序
        ORDER_MAP_ENTRIES_BY_KEYS(false),
    
        // 是否应用Jackson的序列化缓存机制提升性能
        EAGER_SERIALIZER_FETCH(true),
    
        // 确定是否使用对象的真实 JVM-level 标识(false)比较对象标识的功能;或者,equals() 方法。
        USE_EQUALITY_FOR_OBJECT_ID(false);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    DeserializationFeature就是反序列化时,将JSON 字符串转为对象的特征配置,可配置项如下:

        // 是否将浮点数反序列化到BigDecimal
        USE_BIG_DECIMAL_FOR_FLOATS(false),
    
        // 对整型的处理是否使用BigInteger
        USE_BIG_INTEGER_FOR_INTS(false),
    
        // 是否使用Long去装int值
        USE_LONG_FOR_INTS(false),
    
        // 是否使用java的数组去装载JSON数组
        USE_JAVA_ARRAY_FOR_JSON_ARRAY(false),
    
        // 反序列化遇到不认识的属性时是否抛错
        FAIL_ON_UNKNOWN_PROPERTIES(true),
    
        // 对于intlong这种基本类型,若传null (没传)的话是否失败。
        // true:没传就抛出JsonProcessingException 异常; false:没传就使用基本类型的默认值
        FAIL_ON_NULL_FOR_PRIMITIVES(false),
    
        // 反序列化到枚举类型是否允许传数字。true:数字的话就抛出异常
        FAIL_ON_NUMBERS_FOR_ENUMS(false),
    
        // 当传入的是非法的子类型的时候,是否失败。true:抛出异常;false:不管它
        FAIL_ON_INVALID_SUBTYPE(true),
    
        // 读取为树模型的时候,遇上相同的key是否抛异常。
        FAIL_ON_READING_DUP_TREE_KEY(false),
    
        // 是否处理已经被显示标记为忽略的属性
        FAIL_ON_IGNORED_PROPERTIES(false),
    
        // 遇到不能处理的Objectld时候如是否失败
        FAIL_ON_UNRESOLVED_OBJECT_IDS(true),
    
        // 当创建方法(不一定是构造函数)有多个参数,但是有参数的缺失时是否失败
        FAIL_ON_MISSING_CREATOR_PROPERTIES(false),
    
        // 给创建方法的参数传null时,是否失败
        FAIL_ON_NULL_CREATOR_PROPERTIES(false),
    
        // 当标注有(@JsonTypeInfo .As#EXTERNAL_PROPERTY注解的属性没传的时候是否失败
        FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY(true),
    
        // 是否去校验末尾的token。true:会自动多调用一次JsonParser#HnextToken—确保没有token了(如果还要就抛出异常); false:不会进行进—步的校验
        FAIL_ON_TRAILING_TOKENS(false),
    
        // 是否包装异常
        WRAP_EXCEPTIONS(true),
    
        // 单个值是否转为数组
        ACCEPT_SINGLE_VALUE_AS_ARRAY(false),
    
        // 确定是否可以将单值数组(在 JSON 中)值强制转换为相应值类型的功能
        UNWRAP_SINGLE_VALUE_ARRAYS(false),
    
        // 允许“解包”根级 JSON 值的功能
        UNWRAP_ROOT_VALUE(false),
    
        // 接受空字符串扎转为NULL
        ACCEPT_EMPTY_STRING_AS_NULL_OBJECT(false),
    
        //
        ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT(false),
    
        // 浮点类型转为INT
        ACCEPT_FLOAT_AS_INT(true),
    
        // 枚举值的标准反序列化机制的功能:如果启用,则假定枚举已使用 Enum.toString() 的返回值进行序列化
        READ_ENUMS_USING_TO_STRING(false),
    
        // 允许将未知枚举值解析为空值的功能。如果禁用,未知的枚举值将引发异常
        READ_UNKNOWN_ENUM_VALUES_AS_NULL(false),
    
        // 允许忽略未知枚举值和通过 {@link com.fasterxml.jackson.annotation.JsonEnumDefaultValue @JsonEnumDefaultValue} 注释指定的预定义值的功能。
        READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE(false),
    
        // 将日期时间戳读取为纳秒
        READ_DATE_TIMESTAMPS_AS_NANOSECONDS(true),
    
        // 指定是否提供上下文的功能 {@link java.util.TimeZone} ({@link DeserializationContextgetTimeZone()} 应用于在反序列化时调整 DateTime 值,即使值本身包含时区信息
        ADJUST_DATES_TO_CONTEXT_TIME_ZONE(true),
    
    
        // 确定 {@link ObjectReader} 是否应该在可能的情况下急切地获取必要的 {@link JsonDeserializer} 的功能。
        EAGER_DESERIALIZER_FETCH(true);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    MapperFeature则是可以控制JsonMapper0bjectMapper0bjectReaderobjectwriter的映射/绑定行为,可配置项如下:

        // 是否启用使用注解。true:将会使用AnnotationIntrospector去解析注解;false:忽略标注上的注解
        USE_ANNOTATIONS(true),
    
        // 是否可以通过get到集合/映射的引用来修改属性,而不需要专门提供set方法
        USE_GETTERS_AS_SETTERS(true),
    
        // 如何处理被transient修饰的关键字。true:会识别它(不再参与序列化反序列化) , false:忽略这个关键字PROPAGATE_瞬变标记(FALSE):如何处理被瞬态修饰的关键字。真:会识别它(不再参与序列化反序列化),假:忽略这个关键字
        PROPAGATE_TRANSIENT_MARKER(false),
    
        // 是否开启自动检测创建方法的特性。true:会找到public的构造方法 or 只有一个参数的valueOf方法;false:必须使用@JsonCreator注解去指定一个方法用于创建(空的构造方法除外,即使该特征关闭且是private都成)
        AUTO_DETECT_CREATORS(true),
    
        // 是否开启自动检测属性。true:所有的public field成员都会被认为是属性;false:那么只有被标为指定注解的才算(使用@JsonAutoDetect)
        AUTO_DETECT_FIELDS(true),
    
        // true:那么所有的0个参数且以get开头的方法都会被认为是属性;false:只能靠注解
        AUTO_DETECT_GETTERS(true),
    
        // 所有的0个参数且以is开头且返回值是boolean类型的会被认为是属性;false:只能依靠注解
        AUTO_DETECT_IS_GETTERS(true),
    
        // set方法(控制哪些属性可以被set进来)
        AUTO_DETECT_SETTERS(true),
    
        // 如果这个配置为false时,只有存在对应的构造器、setter或者field时,才调用getter。
        REQUIRE_SETTERS_FOR_GETTERS(false),
    
        // 标记为final的field是否也可以被get方法匹配
        ALLOW_FINAL_FIELDS_AS_MUTATORS(true),
    
        // private的field是否也可以被get方法匹配到
        INFER_PROPERTY_MUTATORS(true),
    
        // 是否支持JavaEE的注解@ConstructorProperties,效果同@JsonCreator
        INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES(true),
    
        // 是否允许调用AccessibleObject#setAccessible来让一切set方法or filed属性可以直接访问(注意:若你关闭此特征,也就是开启了权限检查的话,对性能是有较大损耗的,所以一般请不要这么做)
        CAN_OVERRIDE_ACCESS_MODIFIERS(true),
    
        //  针对紧邻的上特征的优化。也就是说若你上面特征开启了的话,理论上所有的权限都要去校验。但此处优化为若是public的话也依旧不执行访问检查了,提高public的整体效率
        OVERRIDE_PUBLIC_ACCESS_MODIFIERS(true),
    
        // 是否使用静态类型。true:使用运行时候的动态类型,false:使用声明时的静态类型
        USE_STATIC_TYPING(false),
    
        // 2.10新增的特征。是否使用BASE_TYPE当作反序列化时的多态类型的默认类型。true:使用;false:不使用。当然你也是可以手动通过@JsonTypeInfo.defaultImpl注解属性来指定的
        USE_BASE_TYPE_AS_DEFAULT_IMPL(false),
    
        // 这个特征和@JsonView息息相关。true:即使没有标注有@JsonView注解的属性,会被应用到所有的视图view里面;false:只有标注有@JsonView的属性才会进入到对应视图里
        DEFAULT_VIEW_INCLUSION(true),
    
        // 是否开启默认的序列化顺序。true:Bean的序列化会按照字母表顺序;false:无序。
        SORT_PROPERTIES_ALPHABETICALLY(false),
    
        // 首先对创建者属性进行排序
        SORT_CREATOR_PROPERTIES_FIRST(true),
    
        // 反序列化时是否对大小写敏感。true:不敏感;false:敏感
        ACCEPT_CASE_INSENSITIVE_PROPERTIES(false),
    
        // 反序列化时是否对大小写敏感。true:不敏感;false:敏感
        ACCEPT_CASE_INSENSITIVE_ENUMS(false),
    
        // 允许解析某些枚举的基于文本的值类型,但忽略大小写的特性。如对date/time的序列化,忽略上面的大小写
        ACCEPT_CASE_INSENSITIVE_VALUES(false),
    
        //  使用包装名称作为属性名称
        USE_WRAPPER_NAME_AS_PROPERTY_NAME(false),
    
        // 是否使用原始输出Bean Name。默认的是false的,是为了保证向下兼容
        USE_STD_BEAN_NAMING(false),
    
        // 是否允许再修改已经被命名的属性名
        ALLOW_EXPLICIT_PROPERTY_RENAMING(false),
    
        // 对scalar的一些类型的适配处理,保持默认开启即可
        ALLOW_COERCION_OF_SCALARS(true),
    
        // 是否开启重复模块的注册
        IGNORE_DUPLICATE_MODULE_REGISTRATIONS(true),
    
        // 对于不能被合并的属性(什么叫不能被合并的属性?)若你要合并时是否忽略。true:忽略它。false:抛出异常
        IGNORE_MERGE_FOR_UNMERGEABLE(true),
    
        // 阻止不安全的多态基类型
        BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES(false),
    
        // 使用默认值
        APPLY_DEFAULT_VALUES(true);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    2、ObjectMapper

    ObjectMapperJackson最重要的一个类,是面向用户的高层API,我们需要进行JSON 转换,指定特征时,直接使用这个对象就可以了。

    Jackson和Fastjson对比

    国内用的比较多的,应该就是Jackson Fastjson了,我们应该怎么选呢?

    首先简单看下他们的使用方式,比如将Java对象序列化为JSON字符串:

    // Fastjson
    String jsonString = JSON.toJSONString(user); 
    // Jackson
    ObjectMapper objectMapper = new ObjectMapper();  
    String jsonString = objectMapper.writeValueAsString(user);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    将JSON字符串反序列化为JavaBean:

    // Fastjson
    Model model = JSON.parseObject(jsonStr, Model.class);
    // Jackson
    ObjectMapper objectMapper = new ObjectMapper();  
    Person person1 = objectMapper.readValue(jsonStr, Person.class);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Fastjson直接使用JSON类的静态方法进行转换操作,Jackson 需要实例化ObjectMapper 对象。
    其他性能、安全方面的测试对比,可以自己在百度搜搜~

    综合来说,二者都是非常优秀且成功的框架,性能上来说,Fastjson可能更受一筹,但是从稳定性、安全性、代码规范性、扩展性来说,Jackson 稍占优势。

    在网上有很多Jackson Fastjson深度对比到底改怎么选的文章,甚至还有阿里出品必属废品公司已经禁用fastjson了种种言论。

    Fastjson作为一个几乎靠温少一人之力扛起来的国产框架,其优秀和成功程度毋庸置疑,多多支持,国产才会进步。

    Spring MVC 中的 JSON

    Spring MVC 是一个WEB 框架,现在大多都是前后端分离开发,而前后端很多接口都是通过application/json进行交互,在进行请求和响应处理时,毫无疑问,肯定要进行对象和JSON转换,比如代码中响应结果都是对象,需要转换为JSON传输给前端。

    Spring MVC 中进行对象转换操作的就是HttpMessageConverter消息转换器,而对JSON 进行转换就是基于Jackson 实现的转换器,这也是默认选项,关于这些内容可以参考Spring MVC系列(8)-HttpMessageConverter之使用分析

    Spring MVC 除了提供基于Jackson 实现的转换器之外,还提供了获取ObjectMapper实例的两个类,一个是构建器,一个是FactoryBean 。
    在这里插入图片描述

    Spring Boot 中的 JSON

    Spring Boot 提供了三个 JSON 库的集成:

    • Gson
    • Jackson
    • JSON-B

    Jackson 是默认首选。

    可以看到在 spring-boot-starter-json 中,包含了Jackson 相关的依赖。
    在这里插入图片描述
    既然默认携带了Jackson,就没有必要额外再费功夫引入另一种 JSON 库了,用默认的就OK了。

    自动配置 Jackson

    Spring Boot 对于Jackson 也提供了自动配置功能。
    在这里插入图片描述

    JacksonProperties

    首先提供了配置属性类JacksonProperties,方便我们直接在YML 配置文件中指定一些转换策略:
    在这里插入图片描述
    全部属性配置如下:

    spring:
      jackson:
        constructor-detector: EXPLICIT_ONLY
        # 设置日志格式化格式,配置为日期格式字符串或完全限定的日期格式类名。例如 yyyy-MM-dd HH:mm:ss
        date-format: yyyy-MM-dd HH:mm:ss
        # 宽松的全局默认设置
        default-leniency: true
        # 控制序列化期间包含的属性。使用 Jackson 的 JsonInclude.Include 枚举中的值之一进行配置。
        default-property-inclusion: always
        # 序列化配置 ,MAP 集合 , Map
        serialization:
          EAGER_SERIALIZER_FETCH: true
        # 反序列化特征,Map
        deserialization:
          USE_BIG_DECIMAL_FOR_FLOATS: true
        # ObjectMapper/JsonMapper特征,Map
        mapper:
          AUTO_DETECT_GETTERS: true
        # 生成器JsonGenerator.Feature,Map
        generator:
          AUTO_CLOSE_TARGET: true
        # 地区
        locale: zh_CN
        # 解析器 Map
        # parser:
        # 设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值,SNAKE_CASE-返回的json驼峰式转下划线,json body下划线传到后端自动转驼峰式
        property-naming-strategy: SNAKE_CASE
        # 全局时区
        time-zone: GMT+8
        # 可见性阈值,可用于限制自动检测哪些方法(和字段)。
        visibility:
          GETTER: ANY
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    Jackson2ObjectMapperBuilderCustomizer

    Jackson2ObjectMapperBuilderCustomizer从字面上理解时一个构造器的定制器,可以实现该接口,给Jackson2ObjectMapperBuilder添加一些配置。

    然后在Spring 容器注册一个该类型的Bean 对象:

        @Bean
        public Jackson2ObjectMapperBuilderCustomizer customizeJackson2ObjectMapper() {
            return builder -> builder
                    .indentOutput(true)
                    .propertyNamingStrategy(PropertyNamingStrategy.PASCAL_CASE_TO_CAMEL_CASE)
                    .simpleDateFormat("yyyyMMdd").build();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在实例化Jackson2ObjectMapperBuilder (Spring MVC 提供的ObjectMapper 构建器)对象的时候,会调用容器中所有的定制器,配置构建者,这也就是提供了一个扩展点,可以使用这种方式定制我们的ObjectMapper

    JacksonAutoConfiguration

    JacksonAutoConfiguration为自动配置类,启动声明了一个定制器,将JacksonProperties中配置的特征等传递给构建器。
    在这里插入图片描述
    注册了一个构建器,并调用所有的定制器的定制方法。

            @Bean
            @Scope("prototype")
            @ConditionalOnMissingBean
            Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext, List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
            	// 创建构建器
                Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
                builder.applicationContext(applicationContext);
                // 调用所有的定制器
                this.customize(builder, customizers);
                return builder;
            }
         private void customize(Jackson2ObjectMapperBuilder builder, List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
                Iterator var3 = customizers.iterator();
    
                while(var3.hasNext()) {
                    Jackson2ObjectMapperBuilderCustomizer customizer = (Jackson2ObjectMapperBuilderCustomizer)var3.next();
                    customizer.customize(builder);
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在自动配置类的static 块中,声明了两个默认特征,序列化时时间格式的数据不使用时间戳的方式,而原本的配置是true

        static {
            Map<Object, Boolean> featureDefaults = new HashMap();
            featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            featureDefaults.put(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
            FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    最重要的是,可以看到Spring Boot 为我们注册了一个单例ObjectMapper 到容器中,是线程安全的,所以在使用Spring Boot 时不要再傻乎乎的去new 了~~~~

            @Bean
            @Primary
            @ConditionalOnMissingBean
            ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
                return builder.createXmlMapper(false).build();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    使用Mybatis数据库逆向生成工具
    图像处理:Python使用OpenCV进行图像锐化 (非锐化掩模、拉普拉斯滤波器)
    react 使用 craco库 配置 @ 路径,以及 jsconfig.json或者tsconfig.json 配置智能提示
    【HTML学生作业网页】基于HTML+CSS+JavaScript仿南京师范大学泰州学院(11页)
    代码托管你只知道 GitHub?
    Jenkin 添加节点报错No Known Hosts file was found
    架构师的 36 项修炼第10讲:架构实战案例分析
    苹果酸-壳聚糖纳米孔水凝胶微球/SA/CS/GT三元复合/载血小板源性生长因子壳聚糖水凝胶微球
    一本通1075;药房管理
    R基础运算
  • 原文地址:https://blog.csdn.net/qq_43437874/article/details/125975939