2016-03-29 11 views
2

Ich möchte beide einen benutzerdefinierten Serializer verwenden und haben die JsonInclude.Include.NON_DEFAULT Bezeichnung geehrt werden. Wenn ich keinen benutzerdefinierten Serialisierer verwende, wird dieser beachtet, aber wenn ich einen benutzerdefinierten Serializer verwende, ist dies nicht der Fall.JsonInclude.Include.NON_DEFAULT funktioniert nicht mit benutzerdefinierten Serializer

Dies ist Jackson 2.2.2. Ich habe derzeit keine Möglichkeit, zu einer neueren Version von Jackson zu wechseln.

Hier ist ein einfaches Beispiel, das das Problem zeigt:

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

Und hier ist der Ausgang:

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

Beachten Sie, dass f selbst wird serialisiert wird, wenn es den Standardwert hat. Wenn ich die @JsonSerialize Anmerkung kommentieren Sie dann bekomme ich folgende Ausgabe:

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

Dann f richtig funktioniert nicht serialisiert bekommen. Aber natürlich werden Dinge nicht in dem von mir gewünschten Format serialisiert.

Also wie bekomme ich den benutzerdefinierten Serializer die @JsonInclude Annotation der Klasse zu ehren?

Antwort

2

Sie wollen wahrscheinlich public boolean isEmpty(SerializerProvider provider, T value) gemäß der documentation, implementieren, die sagt:

public boolean isEmpty (SerializerProvider Provider Wert T)

Methode aufgerufen zu prüfen, ob bestimmte serializable Wert betrachtet wird " leerer "Wert" (zur Unterdrückung der Serialisierung leerer Werte).

Die Standardimplementierung berücksichtigt nur Nullwerte als leer.

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

Eine weitere mögliche Fehlerquelle ist, dass Sie über NON_EMPTY reden, aber Sie Code verwendet NON_DEFAULT.


Und eher zu viel im Debugger Graben führt mich

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

vorzuschlagen, die Ihre Tests zu bestehen scheint.

Das Problem scheint in JacksonAnnotationInspector#findSerializationInclusion, zu sein, die zunächst für ein @JsonInclude Attribut auf dem Grundstück sieht, und wenn es das nicht findet, sucht er nach einer @JsonSerialize Anmerkung. @JsonSerialize enthält eine veraltete Eigenschaft include, die einen Standardwert von ALWAYS hat.

Ich habe es nicht zu tief untersucht, aber ich vermute, dass ein Deprecation/Refactor es geschafft hat, einige Funktionen zu entfernen. So ist das Leben.

+0

Es gibt keine Methode mit dieser Signatur auf 'JsonSerializer'. Außerdem frage ich nach 'NON_DEFAULT', nicht' NON_EMPTY'. – QuantumMechanic

+0

Dank für Hinweis auf NON_EMPTY vs. NON_DEFAULT. Ich habe die Frage bearbeitet, um den Fehler in der Frage zu beheben. – QuantumMechanic

+0

Welche Version von Jackson verwenden Sie? Vielleicht möchten Sie sich "public boolean isEmpty (T value)" anschauen. Aber all das spielt keine Rolle, wenn Sie wirklich nach NON_DEFAULT suchen. – ptomli