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.
我既要使用自定义序列化程序,又要尊重 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.