JsonInclude.Include.NON_DEFAULT 无法使用自定义序列化程序

JsonInclude.Include.NON_DEFAULT not working with custom serializer

我既要使用自定义序列化程序,又要尊重 JsonInclude.Include.NON_DEFAULT 指定。当我不使用自定义序列化程序时,它很荣幸,但当我使用自定义序列化程序时,它不是。

这是杰克逊 2.2.2。我目前没有切换到更新版本的 Jackson 的选项。

这是一个说明问题的简单示例:

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.io.IOException;
import java.util.EnumSet;
import java.util.Set;
import java.util.stream.Collectors;    

public class JacksonSerialization
{
    public static void main(String[] args) throws Exception {
        ObjectMapper serializer = new ObjectMapper();

        Foo foo = new Foo();
        foo.setFlags(EnumSet.of(Flag.CC, Flag.BB));
        System.out.println(serializer.writeValueAsString(foo));

        foo = new Foo();
        System.out.println(serializer.writeValueAsString(foo));
    }

    public static enum Flag
    {
        AA,
        BB,
        CC
    }

    @JsonInclude(JsonInclude.Include.NON_DEFAULT)
    public static class Foo
    {
        private Set<Flag> flags;

        public Foo() {
            flags = EnumSet.of(Flag.AA);
        }

        @JsonGetter("f")
        @JsonSerialize(using = FlagSetSerializer.class)
        public Set<Flag> getFlags() {
            return flags;
        }

        public void setFlags(Set<Flag> theFlags) {
            flags = theFlags;
        }
    }

    public static class FlagSetSerializer extends JsonSerializer<Set<Flag>>
    {
        @Override
        public void serialize(Set<Flag> value,
                              JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            String csv = value.stream()
                    .map(Flag::toString)
                    .collect(Collectors.joining(","));
            jsonGenerator.writeString(csv);
        }
    }
}

这是输出:

{"f":"BB,CC"}
{"f":"AA"}

请注意,即使 f 具有默认值,它也会被序列化。如果我注释掉 @JsonSerialize 注释,则会得到以下输出:

{"f":["BB","CC"]}
{}

然后 f 正确地 得到序列化。但是当然事情并没有按照我想要的格式进行序列化。

那么我如何获得自定义序列化程序以遵守 class 的 @JsonInclude 注释?

您可能希望根据 documentation 实施 public boolean isEmpty(SerializerProvider provider, T value),其中表示:

public boolean isEmpty(SerializerProvider provider, T value)

Method called to check whether given serializable value is considered "empty" value (for purposes of suppressing serialization of empty values).

Default implementation will consider only null values to be empty.

根据https://github.com/FasterXML/jackson-databind/issues/730

另一个可能的麻烦来源是你谈论 NON_EMPTY 但你的代码使用 NON_DEFAULT.


在调试器中深入挖掘导致我提出建议

@JsonSerialize(using = FlagSetSerializer.class, include = JsonSerialize.Inclusion.NON_DEFAULT)

这似乎通过了您的测试。

问题似乎在JacksonAnnotationInspector#findSerializationInclusion,它首先在属性上寻找一个@JsonInclude属性,当它失败时要找到它,它会查找 @JsonSerialize 注释。 @JsonSerialize 包含已弃用的 include 属性,其默认值为 ALWAYS

我没有深入研究它,但我怀疑 deprecation/refactor 设法切断了一些功能。 C'est la vie.