2017-09-13 5 views
3

Ich versuche, Optional in einem POJO zu verwenden, um anzuzeigen, wenn ein JSON-Feld null, abwesend oder vorhanden sein kann. Mein Problem ist, dass ich nicht herausfinden kann, wie man jackson so konfiguriert, dass Optional.empty() und null nicht gleich behandelt werden. Für empty() möchte ich das Feld ignoriert werden. Keiner der JsonInclude-Werte scheint dies zu tun. Jdk8Module#configureAbsentsAsNulls() sah vielversprechend aus, aber es ändert nicht die Ergebnisse meiner Tests. Gibt es eine Möglichkeit, dies zu tun?Jackson optionales Feld leer() vs null

tl; dr null Werte sollte serialisiert werden, Optional.empty() sollte nicht serialisiert werden.

Hier sind einige Tests, die das Verhalten zeigen, das ich versuche zu erreichen.

class POJO { 
    public Optional<String> content; 
} 

private ObjectMapper getMapper() { 
    return new ObjectMapper().registerModule(new Jdk8Module()); 
} 

@org.junit.Test 
public void testAbsent() throws JsonProcessingException { 
    ObjectMapper mapper = getMapper(); 

    POJO pojo = new POJO(); 
    pojo.content = Optional.empty(); 

    String result = mapper.writeValueAsString(pojo); 

    assertEquals("{}", result); 
} 

@org.junit.Test 
public void testNull() throws JsonProcessingException { 
    ObjectMapper mapper = getMapper(); 

    POJO pojo = new POJO(); 
    pojo.content = null; 

    String result = mapper.writeValueAsString(pojo); 

    assertEquals("{\"content\":null}", result); 
} 

@org.junit.Test 
public void testPresent() throws JsonProcessingException { 
    ObjectMapper mapper = getMapper(); 

    POJO pojo = new POJO(); 
    pojo.content = Optional.of("Hello"); 

    String result = mapper.writeValueAsString(pojo); 

    assertEquals("{\"content\":\"Hello\"}", result); 
} 
+0

bitten Sie daher ein minimales Beispiel schreiben Testfall, den Sie voraussichtlich bestehen, aber nicht erfolgreich ist (z. B. den Mapper konfigurieren, ein Feld auf leer setzen, serialisieren, Ausgabe anzeigen)? – chrylis

+0

Nur einige Tests hinzugefügt. Entschuldigung, sie waren nicht dort, um damit zu beginnen. – Panda

+0

Wie ich in der ursprünglichen Frage sagte (und wie in den Tests angegeben), sollte null serialisiert werden und leer() sollte nicht. Dies ist nicht das Standardverhalten des Moduls. Diese Frage beantwortet nicht, wie man dieses Verhalten erreicht. – Panda

Antwort

0

Wenn Sie die Jackson-Dokumentation @JsonInclude Anmerkung here überprüfen, die verwendet wird, um festzulegen, welche auf den Feldern Werte basierend ignoriert oder serialisiert werden Felder sollten, können Sie sehen, dass es ein paar Parameter (NON_ABSENT und NON_EMPTY), die verwendet werden können, um Optional.empty Werte zu ignorieren, aber sie werden zusammen mit null Werte kombiniert, so dass sie in Ihrem Fall nicht funktionieren.

Was Sie tun können, ist eine JsonFilter erstellen, um den Wert der Felder zu überprüfen und sie zu ignorieren, wenn sie Optional.empty sind.

PropertyFilter optionalFilter = new SimpleBeanPropertyFilter() { 

    @Override 
    public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception { 
     // get the field using the writer's name (field name) 
     Field field = pojo.getClass().getDeclaredField(writer.getFullName().toString()); 

     // get the value of the field, by making it accessible and then reverting 
     boolean defaultAccess = field.isAccessible(); 
     field.setAccessible(true); 
     Object value = field.get(pojo); 
     field.setAccessible(defaultAccess); 

     // serialize if null or it is not Optional.empty 
     if (value == null || value.equals(Optional.empty()) == false) { 
      writer.serializeAsField(pojo, jgen, provider); 
     } 
    } 
}; 

Dies wird jedes Feld der Klasse überprüfen und serialisiert werden, wenn es null oder etwas anderes als Optional.empty ist.

Verwenden es in der Hauptklasse:

FilterProvider filters = new SimpleFilterProvider().addFilter("optionalFilter", optionalFilter); 

// note that you need the `Jdk8Module` module to get the value of the optional 
ObjectMapper mapper = new ObjectMapper().registerModule(new Jdk8Module()); 

POJO pojo = new POJO(); 
pojo.setContent(Optional.empty()); 

System.out.println(mapper.writer(filters).writeValueAsString(pojo)); 

pojo = new POJO(); 
pojo.setContent(null); 

System.out.println(mapper.writer(filters).writeValueAsString(pojo)); 

pojo = new POJO(); 
pojo.setContent(Optional.of("Hello")); 

System.out.println(mapper.writer(filters).writeValueAsString(pojo)); 

muß auch die Klasse mit dem Filter mit Anmerkungen versehen:

@JsonFilter("optionalFilter") 
class POJO { 

} 

Ausgang:

{} 
{"content":null} 
{"content":"Hello"} 
Verwandte Themen