问题
I want to both use a custom serializer and have the JsonInclude.Include.NON_DEFAULT
designation be honored. When I don't use a custom serializer it is honored but when I do use a custom serializer it is not.
This is Jackson 2.2.2. I do not presently have the option to switch to a newer version of Jackson.
Here's a simple example that shows the problem:
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);
}
}
}
And here's the output:
{"f":"BB,CC"}
{"f":"AA"}
Note that f
is being serialized even when it has the default value. If I comment out the @JsonSerialize
annotation then I get the following output:
{"f":["BB","CC"]}
{}
Then f
properly does not get serialized. But of course things are not being serialized in the format I want.
So how do I get the custom serializer to honor the class's @JsonInclude
annotation?
回答1:
You probably want to implement public boolean isEmpty(SerializerProvider provider, T value)
as per the documentation, which says:
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.
As per https://github.com/FasterXML/jackson-databind/issues/730
Another possible source of trouble is that you talk about NON_EMPTY
but you code uses NON_DEFAULT
.
And rather too much digging in the debugger leads me to suggest
@JsonSerialize(using = FlagSetSerializer.class, include = JsonSerialize.Inclusion.NON_DEFAULT)
Which seems to pass your tests.
The problem seems to be in JacksonAnnotationInspector#findSerializationInclusion
, which first looks for a @JsonInclude
attribute on the property, and when it fails to find that, it looks for a @JsonSerialize
annotation. @JsonSerialize
includes a deprecated include
property, which has a default value of ALWAYS
.
I've not looked into it too deeply, but I suspect a deprecation/refactor managed to slice off some functionality. C'est la vie.
来源:https://stackoverflow.com/questions/36288834/jsoninclude-include-non-default-not-working-with-custom-serializer