JsonMappingException: Nessun costruttore adatto trovato per tipo : imansible creare un’istanza dall’object JSON

Sto ottenendo il seguente errore quando tento di ottenere una richiesta JSON ed elaborarla:

org.codehaus.jackson.map.JsonMappingException: Nessun costruttore adatto trovato per tipo [tipo semplice, class com.myweb.ApplesDO]: non è ansible creare un’istanza dall’object JSON (è necessario aggiungere / abilitare le informazioni sul tipo?)

Ecco il JSON che sto cercando di inviare:

{ "applesDO" : [ { "apple" : "Green Apple" }, { "apple" : "Red Apple" } ] } 

In Controller, ho la seguente firma del metodo:

 @RequestMapping("showApples.do") public String getApples(@RequestBody final AllApplesDO applesRequest){ // Method Code } 

AllApplesDO è un wrapper di ApplesDO:

 public class AllApplesDO { private List applesDO; public List getApplesDO() { return applesDO; } public void setApplesDO(List applesDO) { this.applesDO = applesDO; } } 

ApplesDO:

 public class ApplesDO { private String apple; public String getApple() { return apple; } public void setApple(String appl) { this.apple = apple; } public ApplesDO(CustomType custom){ //constructor Code } } 

Penso che Jackson non sia in grado di convertire JSON in oggetti Java per sottoclassi. Si prega di aiutare con i parametri di configurazione per Jackson per convertire JSON in oggetti Java. Sto usando Spring Framework.

EDIT: incluso il bug principale che sta causando questo problema nella class di esempio sopra – Si prega di guardare la risposta accettata per la soluzione.

Così, finalmente ho capito qual è il problema. Non è un problema di configurazione di Jackson come ho dubitato.

In realtà il problema era nella class ApplesDO :

 public class ApplesDO { private String apple; public String getApple() { return apple; } public void setApple(String apple) { this.apple = apple; } public ApplesDO(CustomType custom) { //constructor Code } } 

C’era un costruttore personalizzato definito per la class che lo rendeva il costruttore predefinito. L’introduzione di un fittizio costruttore ha reso l’errore di andare via:

 public class ApplesDO { private String apple; public String getApple() { return apple; } public void setApple(String apple) { this.apple = apple; } public ApplesDO(CustomType custom) { //constructor Code } //Introducing the dummy constructor public ApplesDO() { } } 

Questo succede per questi motivi:

  1. la tua class interiore dovrebbe essere definita come statica

     private static class Condition { //jackson specific } 
  2. Potrebbe essere che non hai costruttore predefinito nella tua class ( UPDATE: Questo non sembra essere il caso)

     private static class Condition { private Long id; public Condition() { } // Setters and Getters } 
  3. Potrebbe essere che i tuoi Setter non sono definiti correttamente o non sono visibili (ad esempio, il setter privato)

Vorrei aggiungere un’altra soluzione a questo che non richiede un costruttore fittizio. Poiché i fittizi costruttori sono un po ‘disordinati e successivamente confusi. Possiamo fornire un costruttore sicuro e annotando gli argomenti del costruttore permettiamo a Jackson di determinare il mapping tra il parametro del costruttore e il campo.

quindi funzionerà anche il seguente. Nota che la stringa all’interno dell’annotazione deve corrispondere al nome del campo.

 import com.fasterxml.jackson.annotation.JsonProperty; public class ApplesDO { private String apple; public String getApple() { return apple; } public void setApple(String apple) { this.apple = apple; } public ApplesDO(CustomType custom){ //constructor Code } public ApplesDO(@JsonProperty("apple")String apple) { } } 

Quando mi sono imbattuto in questo problema, è stato il risultato del tentativo di utilizzare una class interiore per fungere da DO. La costruzione della class interna (silenziosamente) richiedeva un’istanza della class che chiudeva – che non era disponibile per Jackson.

In questo caso, lo spostamento della class interna nel proprio file .java ha risolto il problema.

Puoi per favore testare questa struttura. Se ricordo bene, puoi usarlo in questo modo:

 { "applesRequest": { "applesDO": [ { "apple": "Green Apple" }, { "apple": "Red Apple" } ] } } 

In secondo luogo, si prega di aggiungere costruttore di default a ciascuna class che potrebbe anche aiutare.

Regola pollice : aggiungi un costruttore predefinito per ogni class che hai usato come class di mapping. Ti sei perso questo e il problema sorge!
Basta aggiungere il costruttore predefinito e dovrebbe funzionare.

Devi creare un costruttore fittizio vuoto nella nostra class modello. Così mentre mappi json, viene impostato dal metodo setter.

Se si avvia l’annotazione del costruttore, è necessario annotare tutti i campi.

Nota, il mio campo Staff.name è mappato su “ANOTHER_NAME” nella stringa JSON.

  String jsonInString="{\"ANOTHER_NAME\":\"John\",\"age\":\"17\"}"; ObjectMapper mapper = new ObjectMapper(); Staff obj = mapper.readValue(jsonInString, Staff.class); // print to screen public static class Staff { public String name; public Integer age; public Staff() { } //@JsonCreator - don't need this public Staff(@JsonProperty("ANOTHER_NAME") String n,@JsonProperty("age") Integer a) { name=n;age=a; } } 

Devi capire quali opzioni Jackson ha a disposizione per la deserializzazione. In Java, i nomi degli argomenti del metodo non sono presenti nel codice compilato. Ecco perché Jackson non può generalmente utilizzare i costruttori per creare un object ben definito con tutto ciò che è già impostato.

Quindi, se c’è un costruttore vuoto e ci sono anche setter, usa il costruttore e i setter vuoti. Se non ci sono setter, si usa una magia oscura (riflessi) per farlo.

Se si desidera utilizzare un costruttore con Jackson, è necessario utilizzare le annotazioni come indicato da @PiersyP nella sua risposta. Puoi anche usare un modello di builder. Se incontri qualche eccezione, buona fortuna. La gestione degli errori in Jackson fa schifo, è difficile capirlo in termini di errore nei messaggi di errore.

Anche i serializzatori / deserializzatori jackson personalizzati potrebbero essere il problema. Anche se non è il tuo caso, vale la pena menzionarlo.

Ho affrontato la stessa eccezione e questo è stato il caso.

Per me, questo funzionava, ma l’aggiornamento delle librerie ha causato la comparsa di questo problema. Il problema stava avendo una class come questa:

 package example.counter; import javax.validation.constraints.NotNull; import lombok.Data; @Data public class CounterRequest { @NotNull private final Integer int1; @NotNull private final Integer int2; } 

Usando il lombok:

  org.projectlombok lombok 1.18.0  

Ritornando a

  org.projectlombok lombok 1.16.10  

Risolto il problema. Non so perché, ma volevo documentarlo per il futuro.