Jackson中DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT和ACCEPT_EMPTY_STRING_AS_NULL_OBJECT
文章目錄
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_STRING_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”異常。
總結
- DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT是對POJO、Map、集合、陣列有效,而不是一個普通的string型別欄位。
- DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT在Java中不能達到預期的效果。
相關文章
- Jackson中的ConstructorDetector指南Struct
- SpringBoot中,使用 fastjson代替jacksonSpring BootASTJSON
- 記錄Jackson和Lombok的坑Lombok
- 【淺度渣文】Jackson之jackson-annotations
- 【淺度渣文】Jackson之jackson-databind
- Jackson 庫中@JsonProperty和@JsonAlias註解實現序列化反序列化JSON
- Caused by: com.fasterxml.jackson.databind.JsonMappingException: Incompatible Jackson version: 2.7.3ASTXMLJSONAPPException
- Jackson - 淺析@JsonIncludeJSON
- Json工具類----JacksonJSON
- jackson快速入門
- SpringBoot中的Jackson中日期反序列化問題Spring Boot
- Java中將 Jackson JsonNode 轉換為型別化集合JavaJSON型別
- 使用 Jackson 序列化和反序列化 java.sql.BlobJavaSQL
- Jackson原理探究—Mixins其一
- Jackson多型序列化多型
- Spring Boot2中如何優雅地個性化定製JacksonSpring Boot
- SpringBoot 專案中配置多個 Jackson 的 ObjectMapper ,以及配置遇到的坑Spring BootObjectAPP
- jackson時間格式的處理
- JsonUtil(基於Jackson的實現)JSON
- Jackson(3)之常用註解使用
- springboot 結合jackson資料脫敏Spring Boot
- Jackson Redisson反序列化問題Redis
- jackson學習之三:常用API操作API
- jackson學習之一:基本資訊
- jackson學習之五:JsonInclude註解JSON
- JSON解析器之Gson、FastJson、JacksonJSONAST
- 終極CRUD-3-用Jackson解析jsonJSON
- 一文搞定Jackson解析JSON資料JSON
- jackson學習+CVE-2019-12086漏洞分析
- jackson學習之八:常用方法註解
- jackson學習之七:常用Field註解
- 設定Springboot返回jackson資料序列化Spring Boot
- jackson學習之九:springboot整合(配置檔案)Spring Boot
- Jackson精解第4篇-@JacksonInject與@JsonAlias註解JSON
- jackson學習之四:WRAP_ROOT_VALUE(root物件)物件
- jackson學習之十(終篇):springboot整合(配置類)Spring Boot
- 利用Jackson序列化實現資料脫敏
- spring.jackson.default-property-inclusion 不生效問題分析Spring