一、依赖版本

jackson-databind-2.8.10

二、MapperFeature.USE_GETTERS_AS_SETTERS的作用

源码解释

    /*** Feature that determines whether otherwise regular "getter"* methods (but only ones that handle Collections and Maps,* not getters of other type)* can be used for purpose of getting a reference to a Collection* and Map to modify the property, without requiring a setter* method.* This is similar to how JAXB framework sets Collections and* Maps: no setter is involved, just setter.*<p>* Note that such getters-as-setters methods have lower* precedence than setters, so they are only used if no* setter is found for the Map/Collection property.*<p>* Feature is enabled by default.*/USE_GETTERS_AS_SETTERS(true)

USE_GETTERS_AS_SETTERS开启时,针对Map和Collection类型的属性可以用getter防获取属性的引用来改变属性的值,不需要setter方法。

反序列化:在目标类中,用我们期望的值,修改那些可以被修改的属性值。正常的属性都是通过setter进行属性赋值,而Collection和Map可以直接用getter获取到属性的引用以此直接修改属性值,所以当USE_GETTERS_AS_SETTERS开启时,ObjectMapper认为Map和Collection这两种值,也应当被反序列化。

三、示例

创建一个用户类。

只有一个getAddresses方法,并没有addresses属性

package deserialize;import java.util.ArrayList;
import java.util.List;public class User {private Long id;private String name;public List<String> getAddresses() {List<String> list = new ArrayList<>();list.add("asd");return list;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}
}

序列化时,ObjectMapper会将addresses作为属性加到为JSON里(如果没有addresses属性,我认为完全可以不序列化)。

  • 开启MapperFeature.USE_GETTERS_AS_SETTERS(默认开启)进行测试, 代码如下:
    @Testpublic void serialize() throws IOException {ObjectMapper objectMapper = new ObjectMapper();// 关闭USE_GETTERS_AS_SETTERS 会报错找不到属性,正常属性用// com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet赋值// 开启时找到属性执行方法就结束,会调用com.fasterxml.jackson.databind.deser.impl.SetterlessProperty.deserializeAndSet// 该方法执行完结束
//        objectMapper.disable(MapperFeature.USE_GETTERS_AS_SETTERS);User user = new User();user.setId(1L);user.setName("zhang");String s = objectMapper.writeValueAsString(user);System.out.println(s);Object value = objectMapper.readValue(s, User.class);System.out.println(value);}

运行结果:

此时,调用ObjectMapper.readValue进行反序列化,正常。

  • 关闭MapperFeature.USE_GETTERS_AS_SETTERS(默认开启)进行测试, 代码如下:
    @Testpublic void serialize() throws IOException {ObjectMapper objectMapper = new ObjectMapper();// 关闭USE_GETTERS_AS_SETTERS 会报错找不到属性,正常属性用// com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet赋值// 开启时找到属性执行方法就结束,会调用com.fasterxml.jackson.databind.deser.impl.SetterlessProperty.deserializeAndSet// 该方法执行完结束objectMapper.disable(MapperFeature.USE_GETTERS_AS_SETTERS);User user = new User();user.setId(1L);user.setName("zhang");String s = objectMapper.writeValueAsString(user);System.out.println(s);Object value = objectMapper.readValue(s, User.class);System.out.println(value);}

运行结果:

此时,调用ObjectMapper.readValue进行反序列化,抛出异常,无法识别addresses属性。

四、反序列化ObjectMapper.readValue源码分析

1、反序列化过程

com.fasterxml.jackson.databind.ObjectMapper#readValue(java.lang.String, java.lang.Class<T>)

com.fasterxml.jackson.databind.ObjectMapper#_readMapAndClose

// 获取反序列化器

com.fasterxml.jackson.databind.ObjectMapper#_findRootDeserializer

// 进行反序列化

com.fasterxml.jackson.databind.deser.BeanDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)

// 反序列化

com.fasterxml.jackson.databind.deser.BeanDeserializer#vanillaDeserialize

    private final Object vanillaDeserialize(JsonParser p,DeserializationContext ctxt, JsonToken t)throws IOException{final Object bean = _valueInstantiator.createUsingDefault(ctxt);// [databind#631]: Assign current value, to be accessible by custom serializersp.setCurrentValue(bean);if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {String propName = p.getCurrentName();do {p.nextToken();// MapperFeature.USE_GETTERS_AS_SETTERS 开启时(默认开启), 执行该方法会返回SetterlessProperty对象,无事发生// MapperFeature.USE_GETTERS_AS_SETTERS 关闭时,该值为空 会抛出异常SettableBeanProperty prop = _beanProperties.find(propName);if (prop != null) { // normal casetry {// 反序列化中的_beanProperties存在该属性值,该属性值就会被赋值, 但是只有一个getter没有字段定义,则无事发生prop.deserializeAndSet(p, ctxt, bean);} catch (Exception e) {wrapAndThrow(e, bean, propName, ctxt);}continue;}// 抛出异常handleUnknownVanilla(p, ctxt, bean, propName);} while ((propName = p.nextFieldName()) != null);}return bean;}

遍历目标类User中所有的属性名propName(因为存在getAddresses方法,jackson这里认为包含addresses属性)。如果在com.fasterxml.jackson.databind.deser.BeanDeserializerBase#_beanProperties中存在该属性则进行属性赋值,否则调用com.fasterxml.jackson.databind.deser.BeanDeserializerBase#handleUnknownVanilla方法抛出异常。

这里先放结论:

  • MapperFeature.USE_GETTERS_AS_SETTERS开启,_beanProperties中存在addresses的属性,所以程序可以正常执行,但由于在User类中没有该属性,所以就有了上面的反序列化的结果(addresses并没有用)。
  • 反之,_beanProperties中不存在addresses的属性,所以会走到handleUnknownVanilla抛出异常

_beanProperties是反序列化器com.fasterxml.jackson.databind.deser.BeanDeserializer的父类com.fasterxml.jackson.databind.deser.BeanDeserializerBase中的属性,下面看反序列化器,是如何创建的。

2、创建反序列化器

com.fasterxml.jackson.databind.ObjectMapper#readValue(java.lang.String, java.lang.Class<T>)

com.fasterxml.jackson.databind.ObjectMapper#_readMapAndClose

// 获取反序列化器

com.fasterxml.jackson.databind.ObjectMapper#_findRootDeserializer

com.fasterxml.jackson.databind.DeserializationContext#findRootValueDeserializer

com.fasterxml.jackson.databind.deser.DeserializerCache#findValueDeserializer

// 创建并缓存反序列化器

com.fasterxml.jackson.databind.deser.DeserializerCache#_createAndCacheValueDeserializer

com.fasterxml.jackson.databind.deser.DeserializerCache#_createAndCache2

// 创建反序列化器

com.fasterxml.jackson.databind.deser.DeserializerCache#_createDeserializer

com.fasterxml.jackson.databind.deser.DeserializerCache#_createDeserializer2

// 创建实例的反序列化器

com.fasterxml.jackson.databind.deser.BeanDeserializerFactory#createBeanDeserializer

// 构建实例的反序列化器

com.fasterxml.jackson.databind.deser.BeanDeserializerFactory#buildBeanDeserializer

// 添加实例的属性到序列化器中,这里添加的属性就是向上文的_beanProperties中赋值

com.fasterxml.jackson.databind.deser.BeanDeserializerFactory#addBeanProps

在addBeanProps方法中有这样一段代码

// 遍历实例的属性定义  只要存在getter属性定义就会有值// At which point we still have all kinds of properties; not all with mutators:for (BeanPropertyDefinition propDef : propDefs) {SettableBeanProperty prop = null;/* 18-Oct-2013, tatu: Although constructor parameters have highest precedence,*   we need to do linkage (as per [databind#318]), and so need to start with*   other types, and only then create constructor parameter, if any.*/if (propDef.hasSetter()) {JavaType propertyType = propDef.getSetter().getParameterType(0);prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);} else if (propDef.hasField()) {JavaType propertyType = propDef.getField().getType();prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);} else if (useGettersAsSetters && propDef.hasGetter()) {// 如果useGettersAsSetters开启 并且有getter则认为该属性需要被反序列化/* May also need to consider getters* for Map/Collection properties; but with lowest precedence*/AnnotatedMethod getter = propDef.getGetter();// should only consider Collections and Maps, for now?Class<?> rawPropertyType = getter.getRawType();if (Collection.class.isAssignableFrom(rawPropertyType)|| Map.class.isAssignableFrom(rawPropertyType)) {// 构造SetterlessProperty对象prop = constructSetterlessProperty(ctxt, beanDesc, propDef);}}

遍历实例中的属性定义(因为存在getAddresses方法,所以这里有三个值id,name和addresses)。

如果该属性有setter方法或者有该属性,都会构造出一个com.fasterxml.jackson.databind.deser.SettableBeanProperty对象;

如果USE_GETTERS_AS_SETTERS开启,并且有getter方法,并且该属性的类型是Collection或者Map,会构造一个com.fasterxml.jackson.databind.deser.impl.SetterlessProperty对象,以上对象都用prop来保存。如果prop不为空则会将该属性加到反序列化器中的_beanProperties中,到反序列化时,程序会正常运行;当prop为空时,则不会加入到_beanProperties中,到反序列化时,会抛出无法识别属性的异常。

五、结论

对于存在getter方法,而没有对应属性值的类进行序列化时,会将getter方法对应的属性值一起序列化,转成json。

对于存在getter方法的并且getter方法的返回值是Map或者Collection类型的类,进行序列化后,反序列化时,如果开启USE_GETTERS_AS_SETTERS,则会正常运行;如果关闭USE_GETTERS_AS_SETTERS则会抛出异常。

如有错误,欢迎指正。

源码地址:https://gitee.com/zhang-dj/jackson-databind-jackson-databind-2.8.10

针对文章内容自己加了一些注释

ObjectMapper中MapperFeature.USE_GETTERS_AS_SETTERS对反序列化的影响相关推荐

  1. java 自定义反序列化_java – 使用类字段中指定的自定义反序列化器反序列化字符串...

    我需要编写一个方法,它接受一些对象,一些字段名称fieldName存在于给定对象的类中,以及一些字段值.该值是字段的 JSON序列化形式.该方法应取值并相应地反序列化,如下所示: static voi ...

  2. 开源组件 Ehcache中被曝严重漏洞,影响多款Jira产品

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 Atlassian 公司督促企业客户修复其 Jira Data Center 和 Jira Service Management Data ...

  3. fileinputstream自定义类序列化和反序列化_Rest Assured篇:Java中的序列化和反序列化...

    点击上方蓝字设为星标 每天傍晚伴你一起成长! Java 中的序列化和反序列化是一个重要的编程概念.它适用于所有主要的编程语言.在本章中,我们将尝试在Java语言的上下文中理解此概念.在本章的最后,我们 ...

  4. python中常用的序列化模块_Python中的序列化和反序列化

    为什么要序列化 内存中的字典.列表.集合以及各种对象,如何保存到一个文件中. 设计一套协议,按照某种规则,把内存中的数据保存到文件中,文件是一个个字节序列.所以必须把数据额转换为字节序列,输出到文件, ...

  5. mysql修改索引对交易影响吗_MySQL中字符串索引对update的影响分析

    本文分析了mysql中字符串索引对update的影响.分享给大家供大家参考,具体如下: 对某一个类型为varchar的字段添加前缀索引后,基于该子段的条件查询时间基本大幅下降:但对于update操作, ...

  6. java 不能反序列化_java中的序列化与反序列化

    序列化就是将一个对象以及他的属性写入一个文件,保存在存中对象的状态 反序列化就是把保存的对象状态再读出来 实现序列化与反序列化就要使用到IO操作中文件的字节流输入与输出 inputStream与out ...

  7. 谈谈:.Net中的序列化和反序列化

    序列化和反序列化相信大家都经常听到,也都会用, 然而有些人可能不知道:.net为什么要有这个东西以及.net Frameword如何为我们实现这样的机制, 在这里我也是简单谈谈我对序列化和反序列化的一 ...

  8. java rest 序列化_Django Rest Framework中的序列化和反序列化

    作为Django REST Framework的新手,我在给我的ModelSerializer中的主键反序列化对象时遇到了问题 . 例如,我有2个扩展ModelSerializer的序列化程序: cl ...

  9. 网络中延迟对主观感受的影响

    T. Hossfeld等人在论文<INITIAL DELAY VS. INTERRUPTIONS: BETWEEN THE DEVIL AND THE DEEP BLUE SEA>中,研究 ...

最新文章

  1. SUSE glibc升级为2.18过程记录
  2. 初学HTML5系列二:HTML5新增的事件属性
  3. 4.Lucene3.案例介绍,创建索引,查询等操作验证
  4. 配置 tsconfig.json
  5. 【转】阿里技术专家详解DDD系列 第二讲 - 应用架构
  6. Linux内核系统架构介绍
  7. EBS 报表输出PDF时中文乱码
  8. SqlServer数据冗余的问题和解决
  9. android应用开发实验报告_聚焦 Android 11: Android 11 应用兼容性
  10. 神经网络控制与matlab仿真,matlab神经网络能做什么
  11. 【MATLAB】 曲面的绘制
  12. 腾讯文档表格内存优化总结
  13. MOX:开创区块链通证参与电影融资的新篇章
  14. 传世私服服务器列表不显示,关于传世私服的人物名字显示设置详解
  15. QT自定义Widget控件及其使用
  16. Python中的模块(二)
  17. ★★★GG口述实录:我和‘老山’英雄的真实接触★★★(PK:★★★MM口述实录:我和程序员老公的幸福生活★★★ )
  18. 根据PPG估算血压利用频谱谱-时间深度神经网络【翻】
  19. PHPMyWind编辑器支持pdf自动上传
  20. proe PTC Pro_Engineer wildfire4.0 M040野火版 DVD32位

热门文章

  1. PostgreSQL数据库统计信息——compute_scalar_stats计算统计数据
  2. 开源库muduo学习-总结篇
  3. 平安iq测试没通过的话影响入职吗_软件测试面试中有哪些潜台词?给你们排雷啦...
  4. redis ,redisson 分布式锁深入剖析
  5. openSCA 开 源 啦 !!!
  6. 使用Swiper插件实现视频轮播,怎么实现切换自动播放视频?
  7. 手机wps系统打印服务器,MK-WPS101w单USB无线打印服务器网页版教程
  8. Beyond compare3.3 绿色版+右键菜单修复方法.rar
  9. 京造k6 68键盘 搜狗输入法冲突
  10. linux指令-ps