jackson - пропустить ключи с нулевыми значениями при сериализации объекта HashMap - PullRequest
0 голосов
/ 24 января 2020

Я пытаюсь сериализовать объект Java с hashmap в строку 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. Я использую версию jackserion 2.9.8

Ответы [ 2 ]

0 голосов
/ 25 января 2020

Когда вы ставите @JsonInclude в поле, это означает, что если поле (не элемент полей) равно null , то оно будет игнорироваться при преобразовании.

  • В вашем случае при использовании @JsonInclude на additionalProperties это означает, что если additionalProperties ( само по себе ) равно нулю, то оно будет игнорироваться при преобразовании .

, поэтому @JsonInclude проверяет только само значение additionalProperties на нулевое значение, но не его элементы.


Пример : Предположим, что у вас есть Ext объект с additionalProperties=null, когда вы хотите его сериализовать, 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

А также вы можете получить * 105 8 * объект из сгенерированной строки. в этом случае ваш объект имеет отфильтрованные дополнительные свойства (не содержит элементов с нулевым ключом или нулевым значением)

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

    }

Solution 2

You Можно написать собственный сериализатор.

Эта ссылка может быть полезна для этой цели

0 голосов
/ 24 января 2020

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