在序列化 HashMap 对象时跳过具有空值的键



我正在尝试使用杰克逊对象映射器将带有哈希映射的Java对象序列化为json字符串。

以下是Ext的类定义 -

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({})
public class Ext implements Serializable {
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap();
private static final long serialVersionUID = -4500317258794294335L;
public Ext() {
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
// ignore toString, equals and hascode
public static class ExtBuilder {
protected Ext instance;
public ExtBuilder() {
if (this.getClass().equals(Ext.ExtBuilder.class)) {
this.instance = new Ext();
}
}
public Ext build() {
Ext result = this.instance;
this.instance = null;
return result;
}
public Ext.ExtBuilder withAdditionalProperty(String name, Object value) {
this.instance.getAdditionalProperties().put(name, value);
return this;
}
}
}

下面是示例测试用例 -

@Test
public void testNullObjectSerialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.setDefaultPropertyInclusion(
JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL));
ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
mapper.writeValue(out, new Ext.ExtBuilder().withAdditionalProperty("unexpected", null).withAdditionalProperty("expected", true).build());
String result = new String(out.toByteArray());
Assert.assertEquals("{"expected":true}", result);
}

我用了

mapper.setDefaultPropertyInclusion(
JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL));` 

通过使用堆栈溢出问题中提供的答案。

我希望结果{"expected":true}但不知何故,结果中包含具有null值的键。

如何解决此问题?

注意:

  1. 代码在github上。
  2. 我正在使用 jacksersion 版本 2.9.8

当您将@JsonInclude放在字段上时,这意味着如果该字段(不是字段的元素(null,那么它将从转换中被忽略。

  • 在您的情况下,当您在additionalProperties上使用@JsonInclude时,这意味着,如果additionalProperties(本身(为 null,那么它将从转换中被忽略。

因此@JsonInclude只检查additionalProperties自身的空值,而不是其元素。


示例:假设您有一个带有additionalProperties=nullExt对象,当您要序列化它时,该additionalProperties被忽略,因为它为null

  • 但在您的方案中,additionalProperties地图的元素包含null,杰克逊不会忽略它们。

解决方案 1

您可以序列化其他属性映射(本身(而不是整个 Ext 对象。

public static void main(String[] args) throws JsonProcessingException {
//Create Ext  Object
Ext ext = new Ext.ExtBuilder().withAdditionalProperty("unexpected", null).withAdditionalProperty("expected", true).build();
//Config
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//Conversion the additionalProperties map (ext.getAdditionalProperties())
String filterMap = mapper.writeValueAsString(ext.getAdditionalProperties());
//Result ({"expected":true})
System.out.println(filterMap);

}
}        

将 JSON 转换为分机对象

你也可以从生成的字符串中获取Ext对象。 在这种情况下,您的对象具有过滤的附加属性(没有任何具有空键或空值的元素(

public static void main(String[] args) throws JsonProcessingException {
//Create Ext  Object
Ext ext = new Ext.ExtBuilder().withAdditionalProperty("unexpected", null).withAdditionalProperty("expected", true).build();
//Config
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//Conversion the additionalProperties map (ext.getAdditionalProperties())
String filterMap = mapper.writeValueAsString(ext.getAdditionalProperties());
//Result ({"expected":true})
System.out.println(filterMap);
//Convert back JSON string to Ext object
Ext filterdExt = mapper.readValue(filterMap, Ext.class);
//Print AdditionalProperties of filterdExt ({"expected":true})
System.out.println(filterdExt.getAdditionalProperties());
}

解决方案 2

可以编写自定义序列化程序。

此链接可能对此有用

WriteValue 不以任何方式考虑包含:它仅适用于 JSON 的写入。 转换是先写后读的顺序;但是在读取完成时,输出不再包含排除的值。

替换此代码:

ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
mapper.writeValue(out, new Ext.ExtBuilder().withAdditionalProperty("unexpected", null).withAdditionalProperty("expected", true).build());
String result = new String(out.toByteArray());
Assert.assertEquals("{"expected":true}", result);

ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
mapper.writeValue(out, mapper.convertValue(new Ext.ExtBuilder().withAdditionalProperty("unexpected", null).withAdditionalProperty("expected", true).build(), Ext.class));
String result = new String(out.toByteArray());
Assert.assertEquals("{"expected":true}", result);

最新更新