Jackson 序列化/反序列化时忽略某属性

基于Spring MVC的RESTful接口基本都使用了Jackson这个类库。

使用过程中总会有
1. 序列化时忽略某属性(如Password)
2. 反序列化时忽略某属性(如HashedPassword)

其实对应在Bean中,就是类的Setter/Getter方法。

Jackson提供了@Jsonignore这个注解,用于在(反)序列化时,忽略bean的某项属性。在Jackson 1.9的时候,@Jsonignore的语义还有了变化,如下:

1.9之前:
在Setter方法上加@Jsonignore注解并不会影响Getter方法的调用

1.9之后:
在Setter方法上加@Jsonignore会导致整个这个属性在序列化过程中被忽略。
https://stackoverflow.com/questions/12505141/only-using-jsonignore-during-serialization-but-not-deserialization

所以在1.9之后需要使用其他的方法来设置某个属性是否需要(反)序列化:
Java代码  收藏代码
  1. @JsonProperty(access = Access.WRITE_ONLY)  


通过设置JsonProperty的access属性来确定当前属性是不是需要自动序列化/反序列化。

WRITE_ONLY:仅做反序列化操作。
READ_ONLY:仅做序列化操作。

现在的问题是,2.8.7版本的jackson databind (start.spring.io在引入Spring-Web-Starter时候自动引入的,版本是Spring Boot 1.5.X-RELEASE), 在使用READ_ONLY时,并没有忽略反序列化操作,查询了一下应该是jackson databind的一个bug:
https://github.com/FasterXML/jackson-databind/issues/95
https://github.com/FasterXML/jackson-databind/issues/935
尽管bug已经关闭,但是似乎还是有问题,这时候有以下Work around在935中有提到:

Java代码  收藏代码
  1. @JsonIgnoreProperties(value="some_field", allowGetters = true, allowSetters = false)  

在类上加上以上注解,工作正常。

注:并未完美解决,似乎JsonIgnoreProperties和JsonIgnore不能共存,这样的话如果某个类既有屏蔽get方法也有屏蔽set方法的话就不知道怎么搞了
另外 https://github.com/FasterXML/jackson-databind/issues/1805 是个比较新的相关bug 跟踪一下。

更新,已经查到问题,由于jackson在处理collection和map时会自动USE_GETTERS_AS_SETTERS,所以会产生问题,引用自己在github的comment:

引用
wwwcomy commented 4 minutes ago • edited
Facing the same problem, in issue #935, seems only simple types were handled correctly.

I looked into the code, the issue was caused by some special logic for USE_GETTERS_AS_SETTERS, in BeanDeserializerFactory Line 565 (version 2.8.10):

Java代码  收藏代码
  1. if (propDef.hasSetter()) {  
  2.                 JavaType propertyType = propDef.getSetter().getParameterType(0);  
  3.                 prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);  
  4.             } else if (propDef.hasField()) {  
  5.                 JavaType propertyType = propDef.getField().getType();  
  6.                 prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);  
  7.             } else if (useGettersAsSetters && propDef.hasGetter()) {  
  8.                 /* May also need to consider getters 
  9.                  * for Map/Collection properties; but with lowest precedence 
  10.                  */  
  11.                 AnnotatedMethod getter = propDef.getGetter();  
  12.                 // should only consider Collections and Maps, for now?  
  13.                 Class<?> rawPropertyType = getter.getRawType();  
  14.                 if (Collection.class.isAssignableFrom(rawPropertyType)  
  15.                         || Map.class.isAssignableFrom(rawPropertyType)) {  
  16.                     prop = constructSetterlessProperty(ctxt, beanDesc, propDef);  
  17.                 }  
  18.             }  

By default USE_GETTERS_AS_SETTERS is enabled, so, although the Collection member was defined Access as "READ_ONLY", still, it is set as a property in the builder instance.

My work around is using (for spring boot applications) spring.jackson.mapper.USE_GETTERS_AS_SETTERS=false

However, I'm not sure this behavior is a bug or not, @cowtowncoder please help to clarify.
posted @ 2019-12-03 18:23  kelelipeng  阅读(5967)  评论(0编辑  收藏  举报