Jackson中DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT和DeserializationFeature. ACCEPT_EMP

Jackson使用过程中的一些疑惑和跟踪。

DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT

首先先来看看这个配置项对应的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.
     *<p>
     * 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}.
     *<p>
     * 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);

注释掉)会发现报错如下:
在这里插入图片描述

DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT

还是先看对应的JavaDoc:

/**
     * Feature that can be enabled to allow empty JSON Array
     * value (that is, <code>[ ]</code>) 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.
     *<p>
     * 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”异常。

总结

  1. DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT是对POJO、Map、集合、数组有效,而不是一个普通的string类型字段。
  2. DeserializationFeature.ACCEPT_EMPTY_ARRA_AS_NULL_OBJECT在Java中不能达到预期的效果。
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值