jackson-skip在序列化hashmap对象时使用空值的键

uoifb46i  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(415)

我正在尝试使用jackson对象Map器将带有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 值包含在结果中。
如何解决此问题?
注:
代码在github上。
我使用的是2.9.8版本的jackersion

yvgpqqbh

yvgpqqbh1#

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);
dohp0rv5

dohp0rv52#

当你把 @JsonInclude 在字段上,这意味着如果字段(不是字段的元素)为空,则转换时将忽略它。
在你使用 @JsonIncludeadditionalProperties 也就是说,如果 additionalProperties (本身)为空,则将从转换中忽略它。
所以呢 @JsonInclude 仅限支票 additionalProperties 它本身表示空值,而不是它的元素。
例如:假设你有一个 Ext 对象 additionalProperties=null ,当您要序列化它时 additionalProperties 被忽略,因为它为空。
但在你的场景中 additionalProperties map包含null,jackson不会忽略它们。
解决方案1
您可以序列化additionalpropertiesMap(本身),而不是整个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对象
而且你还可以 Ext 对象。在本例中,您的对象具有已筛选的additionalproperties(没有任何具有null键或null值的元素)

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
可以编写自定义序列化程序。
此链接可能对此有用

相关问题