2016-07-17 125 views
5

Non proprio sicuro del modo migliore per spiegare il problema, così ho montato lo stesso codice sia di java che di kotlin per una migliore dimostrazione.In Kotlin, Jackson Errore di deserializzazione con classe dati

Quando leggo JSON, sembra che imponga che un valore di bean di dati sia NULL anche se il parametro non è nemmeno parte del json per iniziare e il bean di dati imposta il valore predefinito del campo mancante. In java funziona correttamente senza mai tentare di annullare il valore che non è mai stato fornito per iniziare. In Kotlin sembra che si rompa perché cerca di annullare un campo non annullabile.

In Kotlin

data class Pojo(val name: String, val age: Int, val list: List<String> = emptyList(), val ts: Date = Date()) 

private val mapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()) 
    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) 

fun main(args: Array<String>) { 
    mapper.readValue("""{"name": "John Doe", "list": ["yellow", "green"], "age": 42}""", Pojo::class.java) 
} 

Che genera un'eccezione di

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Pojo.<init>, parameter ts 

In Java (tutto funziona bene)

public class Transform { 
    private static ObjectMapper mapper = new ObjectMapper() 
     .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 

    public static class Pojo { 
    private String name; 
    private int age; 
    private List<String> list; 
    private Date ts = new Date(); 
    <getters and setters for all> 
    } 

    public static void main(String[] args) throws IOException { 
    String json = "{\"name\": \"John Doe\", \"list\": [\"yellow\", \"green\"], \"age\": 42}"; 
    Pojo p = mapper.readValue(json, Pojo.class); 
    System.out.printf("Bean: name=%s, age=%s, list=%s, ts=%s\n", p.name, p.age, p.list, p.ts); 
    } 
} 

Anche se faccio una classe invece di un dato classe in kotlin, ha ancora errori allo stesso modo.

La mia domanda è, come posso ottenere la deserializzazione di Jackson per lavorare a Kotlin con i miei POJO. Il comportamento previsto è che "dovrebbe" interrompersi se viene passato un valore nullo/errato per qualcosa in cui null non è consentito. Ma nello scenario sopra in cui non è stato fatto alcun tentativo di cambiare il campo ts in null, avrebbe dovuto usare il valore di default come fa con java.

L'unica cosa che attraversa la mia mente che sembra funzionare è di non usare il concetto di bean di dati a tutti e di scrivere i miei fagioli come

class Pojo(val name: String, val age: Int) { 
    var list: List<String> = emptyList() 
    var ts: Date = Date() 
} 

Ma poi i miei .equals non funziona ed è consente agli altri a valle di manipolare il contenuto dell'elenco e le proprietà di ts quando voglio che siano di sola lettura.

risposta

10

Con il 2.8.0 rilascio di jackson-kotlin-module esso:

supporta ora utilizzando i valori predefiniti nei metodi costruttori e creatore

L'esempio seguente descrive la funzione di:

data class Question(val title: String = "Is programming hard?", val answer: String) 

val q = mapper.readValue<Question>("""{"answer": "Sure it can be"}""") 
println(q) //-> Question(title=Is programming hard?, answer=Sure it can be) 
+2

Corretto, questa modifica era nuova per 2.8.x e * non può * essere ripristinata su versioni precedenti, quindi è necessario eseguire l'aggiornamento poiché le nuove API sono state aggiunte a Jackson in modo esplicito per dare maggiore controllo ai moduli del plugin. –

+0

Grazie, ha funzionato. Stavo usando 2.7.5 che era l'ultima volta al momento in cui ho iniziato questo piccolo sforzo. Non ho mai pensato che avrei semplicemente dovuto aggiornare le librerie. Felice di una soluzione facile. – Ryba

-1

Penso che una delle proprietà in ingresso siano nulle, quindi sarà necessario inserire ? dopo jsonProperty che potrebbe essere nullo (nel caso in cui questo è il campo della data). È inoltre possibile utilizzare il tipo di dati stringa RAW per il test con virgolette doppie """\unescaped string""" quindi dovrebbe essere come questo val ts: Date? all'interno della classe di dati. E non devi ridichiarare il tipo. risposta così finale sarebbe: data class Pojo(val name: String, val age: Int, val list: List<String>, val ts: Date?)

+1

Ha chiesto informazioni un caso in cui ha un valore predefinito per il parametro, che da Jackson 2.8.0 in avanti (come menziona Miensol) funziona bene. Anche il nullability è più intelligente per quella release. Non avrebbe problemi se usasse 2.8.0. –

Problemi correlati