Jackson: cosa succede se manca una proprietà?

Cosa succede se @JsonProperty un parametro costruttore con @JsonProperty ma Json non specifica quella proprietà. Che valore ottiene il costruttore?

Come faccio a distinguere tra una proprietà che ha un valore nullo rispetto a una proprietà che non è presente nel JSON?

Riassumendo le risposte eccellenti del programmatore Bruce e StaxMan :

  1. Alle proprietà mancanti a cui fa riferimento il costruttore viene assegnato un valore predefinito come definito da Java .

  2. È ansible utilizzare i metodi setter per distinguere tra proprietà impostate in modo implicito o esplicito. I metodi di incastonatore vengono invocati solo per le proprietà con valori espliciti. I metodi di setter possono tenere traccia di se una proprietà è stata impostata in modo esplicito utilizzando un flag booleano (ad esempio isValueSet ).

Cosa succede se annoto un parametro costruttore con @JsonProperty ma Json non specifica quella proprietà. Che valore ottiene il costruttore?

Per domande come questa, mi piace solo scrivere un programma di esempio e vedere cosa succede.

Di seguito è riportato un programma di esempio.

 import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.ObjectMapper; public class JacksonFoo { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); // {"name":"Fred","id":42} String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}"; Bar bar1 = mapper.readValue(jsonInput1, Bar.class); System.out.println(bar1); // output: // Bar: name=Fred, id=42 // {"name":"James"} String jsonInput2 = "{\"name\":\"James\"}"; Bar bar2 = mapper.readValue(jsonInput2, Bar.class); System.out.println(bar2); // output: // Bar: name=James, id=0 // {"id":7} String jsonInput3 = "{\"id\":7}"; Bar bar3 = mapper.readValue(jsonInput3, Bar.class); System.out.println(bar3); // output: // Bar: name=null, id=7 } } class Bar { private String name = "BLANK"; private int id = -1; Bar(@JsonProperty("name") String n, @JsonProperty("id") int i) { name = n; id = i; } @Override public String toString() { return String.format("Bar: name=%s, id=%d", name, id); } } 

Il risultato è che al costruttore viene passato il valore predefinito per il tipo di dati.

Come faccio a distinguere tra una proprietà che ha un valore nullo rispetto a una proprietà che non è presente nel JSON?

Un approccio semplice sarebbe quello di verificare un valore predefinito dopo l’elaborazione di deserializzazione, poiché se l’elemento fosse presente nel JSON ma avesse un valore nullo, il valore nullo sarebbe utilizzato per sostituire qualsiasi valore predefinito dato il corrispondente campo Java. Per esempio:

 import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility; import org.codehaus.jackson.annotate.JsonMethod; import org.codehaus.jackson.map.ObjectMapper; public class JacksonFooToo { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY); // {"name":null,"id":99} String jsonInput1 = "{\"name\":null,\"id\":99}"; BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class); System.out.println(barToo1); // output: // BarToo: name=null, id=99 // {"id":99} String jsonInput2 = "{\"id\":99}"; BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class); System.out.println(barToo2); // output: // BarToo: name=BLANK, id=99 // Interrogate barToo1 and barToo2 for // the current value of the name field. // If it's null, then it was null in the JSON. // If it's BLANK, then it was missing in the JSON. } } class BarToo { String name = "BLANK"; int id = -1; @Override public String toString() { return String.format("BarToo: name=%s, id=%d", name, id); } } 

Un altro approccio sarebbe quello di implementare un deserializzatore personalizzato che controlli gli elementi JSON richiesti. E ancora un altro approccio sarebbe quello di registrare una richiesta di miglioramento con il progetto Jackson su http://jira.codehaus.org/browse/JACKSON

Oltre al comportamento del costruttore spiegato nella risposta di @ Programmer_Bruce, un modo per distinguere tra valore nullo e valore mancante è definire un setter: il setter viene chiamato solo con un valore nullo esplicito. Il setter personalizzato può quindi impostare un flag booleano privato (“isValueSet” o qualsiasi altra cosa) se vuoi tenere traccia dei valori impostati.

I setter hanno la precedenza sui campi, nel caso esistano sia il campo che il setter, così puoi anche “scavalcare” il comportamento in questo modo.

Sto pensando di usare qualcosa nello stile di una class Option, dove un object Nothing potrebbe dirmi se c’è un tale valore oppure no. Qualcuno ha fatto qualcosa del genere con Jackson (in Java, non in Scala, e altri)?

(La mia risposta potrebbe essere utile ad alcune persone che trovano questo thread tramite google, anche se non risponde alla domanda sui PO)
Se hai a che fare con tipi primitivi che sono omessi e non vuoi usare un setter come descritto nelle altre risposte (per esempio se vuoi che il tuo campo sia definitivo), puoi usare gli oggetti box:

 public class Foo { private final int number; public Foo(@JsonProperty Integer number) { if (number == null) { this.number = 42; // some default value } else { this.number = number; } } } 

questo non funziona se il JSON contiene effettivamente null , ma può essere sufficiente se si sa che conterrà solo i primitivi o sarà assente

un’altra opzione è quella di convalidare l’object dopo la deserializzazione manualmente o tramite framework come la convalida dei bean java o, se si utilizza spring, il supporto per la validazione della molla.