Jackson使用过程中的一些疑惑和跟踪。
首先先来看看这个配置项对应的JavaDoc:
/**
* Feature that can be enabled to allow JSON empty String
* value ("") to be bound as `null` for POJOs and other structured
* values ({@link java.util.Map}s, {@link java.util.Collection}s).
* If disabled, standard POJOs can only be bound from JSON `null` or
* JSON Object (standard meaning that no custom deserializers or
* constructors are defined; both of which can add support for other
* kinds of JSON values); if enabled, empty JSON String can be taken
* to be equivalent of JSON null.
*
* NOTE: this does NOT apply to scalar values such as booleans and numbers;
* whether they can be coerced depends on
* {@link MapperFeature#ALLOW_COERCION_OF_SCALARS}.
*
* Feature is disabled by default.
*/
大致意思如下:
它允许将JSON中的空字符串("")作为null值绑定到一个POJO或者Map或者Collection集合对象。如果禁用该配置项,那么值为空字符串的字段在反序列化成一个POJO、Map、Collection时将会报错。
⚠️注意!
不能理解成:他会把JSON字符串中的“空字符串”值在反序列化时转为对象中对应字段的null值。
具体来看下面例子:
public class Address {
private String street;
private String building;
//省略getter/setter
}
public class User {
private Integer id;
private String name;
private String address;
private Address addressObj;
private String[] hobbies;
private Date birthDate;
//省略getter/setter
}
String userStr = "{\"id\":1,\"name\":\"徐健\",\"address\":\"\",\"addressObj\":\"\"}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,true);
User user = objectMapper.readValue(userStr,User.class);
System.out.println(objectMapper.writeValueAsString(user));
如果我们理解成他会把JSON字符串中的“空字符串”值在反序列化时转为对象中对应字段的null值,那么我们期望反序列化之后address的值会从"“变为null,但是并没有,在user对象中address的值依然是”"。
事实上作为Address对象的addressObj在反序列化之后从""变为了null。
因此我们应该正确理解
ACCEPT_EMPTY_STRING_AS_NULL_OBJECT
这个配置项的注释真正要表达的意思,那就是:
空字符串""必须是要绑定到一个POJO、Map、Cpllection、数组这样的对象上(而不是普通的基本类型和String类型)时,才会在反序列化时转为null。
对于上面的例子,我们如果禁用
ACCEPT_EMPTY_STRING_AS_NULL_OBJECT
(将
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,true);
注释掉)会发现报错如下:
还是先看对应的JavaDoc:
/**
* Feature that can be enabled to allow empty JSON Array
* value (that is, [ ]
) to be bound to POJOs (and
* with 2.9, other values too) as `null`.
* If disabled, standard POJOs can only be bound from JSON `null` or
* JSON Object (standard meaning that no custom deserializers or
* constructors are defined; both of which can add support for other
* kinds of JSON values); if enabled, empty JSON Array will be taken
* to be equivalent of JSON null.
*
* Feature is disabled by default.
*
* @since 2.5
*/
大致的意思是:
它允许将JSON中的空数组([])作为null绑定到POJO等其他对象上。
事实真的是这样吗?
还是基于上面的例子稍微改动:
String userStr = "{\"id\":1,\"name\":\"徐健\",\"address\":\"\",\"addressObj\":\"\",\"hobbies\":[]}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT,true);
User user = objectMapper.readValue(userStr,User.class);
System.out.println(objectMapper.writeValueAsString(user));
按照上面的JavaDoc,我们期望JSON字符串里面的hobbies字段在反序列化以后变为null。
但是结果并没有。它依旧被反序列化为了一个length=0的数组
GitHub上有人抛出了同样的问题:ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT does not convert empty JSON array to null value
作者是这么回答的:
Just to make clear: in Jackson documentation, "POJO" means roughly same as "Bean"; Java type that is handled as a set of property/value pairs. This does not include Collections, Maps or arrays (or scalar types). So while naming of ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT is too vague (it really should say POJO), it is not currently intended to coerce [ ] into null for container types.
But more generally I don't think I want to add coercions from JSON Array in cases where such input can be interpreted normally; that is, it is not intended to change empty List/array into Java null value.
I may need to update Javadocs to clarify this behavior.
大致意思如下:
需要说明的是:在Jackson文件中,“ POJO”的含义与“ Bean”大致相同; 作为一组属性/值对处理的Java类型。 这不包括Collections,Maps或数组(或标量类型)。 因此,尽管对ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT的命名过于模糊(实际上应该说是POJO),但对于容器类型,当前不打算将[]强制为null。
但更一般而言,在可以正常解释此类输入的情况下,我不希望从JSON数组添加强制。 也就是说,不打算将空的List / array更改为Java的null。
我可能需要更新Javadocs来阐明此行为。
简单来说,这个配置项并不能把List/array更改为Java的null。
那问题来了,既然不能把list/array转为null,那这个配置项有什么用呢?
作者这么回答的:
I thought use case was clear from document and my comment, but I think this is a bigger misunderstanding than I originally thought. What was intended and implemented is for "coercion" -- implicit conversion from incompatible type -- from (empty) JSON Array into non-array/non-collection type such as POJO or Map or even Scalar, as null.
This was to support some specific platform (PHP I think) that encodes nulls as [ ].
Without setting you would get basic "can not deserialize MyValue from JsonToken.START_ARRAY" exception.
New CoercionConfig (see #2113) will make this bit more clear as well as configurable.
As to converting empty Collection/array into null, which I think is what you want: only the reverse -- converting nulls into "empty", or skipping setting, or throwing Exception -- is possible currently. Functionality for doing that was added because avoiding nulls has been consistently brought up as a use case users want.
Inverse functionality -- making null out of "empty" value -- has been sometimes requested too, I think, but so far no support has been added.
I am always open to possibility of new functionality, features, but in this case it is not a matter of extending something that already is (mechanisms mentioned above are quite specific, partly since null value handling is quite separate from general JsonDeserializer deserialization flow for historical reasons...).
大致意思如下:
我认为用例从文档和评论中都很清楚,但是我认为这是一个比我最初想象的更大的误解。意图和实现的是“强制”(隐式地从不兼容类型转换)从(空)JSON数组作为null到非数组/非集合类型,例如POJO或Map甚至是Scalar。
这是为了支持某些特定的平台(我认为PHP)将null编码为[]。
如果不进行设置,您将获得基本的“无法从JsonToken.START_ARRAY反序列化MyValue”异常。
新的CoercionConfig(请参阅#2113)将使这一点更加清晰和可配置。
至于将空的Collection / array转换为null,我想这就是您想要的:目前只有相反的做法-将null转换为“ empty”,跳过设置或引发Exception。这样做的功能是增加的,因为避免空值一直是用户希望用例提出的。
我认为有时也要求使用逆功能-将“空”值设为null-但到目前为止,尚未添加任何支持。
我总是对新功能和特性的可能性持开放态度,但是在这种情况下,扩展已存在的事物不是问题(上面提到的机制非常具体,部分原因是空值处理与针对历史的一般JsonDeserializer反序列化流程完全不同原因…)。
简而言之,这个选项是为了支持特定平台(PHP等语言)会将null转为[]的情况。如果不设置,在反序列化时会抛出“无法从JsonToken.START_ARRAY反序列化MyValue”异常。