JsonMappingException: nessun costruttore adatto trovato per il tipo [tipo semplice, classe]: impossibile creare un'istanza dall'oggetto JSON


438

Ricevo il seguente errore quando provo a ottenere una richiesta JSON ed elaborarla:

org.codehaus.jackson.map.JsonMappingException: nessun costruttore adatto trovato per il tipo [tipo semplice, classe com.myweb.ApplesDO]: impossibile creare un'istanza dall'oggetto 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> applesDO;

    public List<ApplesDO> getApplesDO() {
        return applesDO;
    }

    public void setApplesDO(List<ApplesDO> 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. 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 classe di esempio sopra - Cerca una risposta accettata per la soluzione.


2
Non vedo alcuna sottoclasse nel codice sopra, è questo il codice che stai provando o stai facendo un esempio più semplice?
gkamal,

Ho aggiunto una risposta con qualche spiegazione in più su come funziona. Fondamentalmente, è necessario rendersi conto che Java non mantiene i nomi degli argomenti del metodo in fase di esecuzione.
Vlasec,

Risposte:


565

Quindi, finalmente ho capito qual è il problema. Non è un problema di configurazione di Jackson, come dubitavo.

In realtà il problema era nella classe 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 classe rendendolo il costruttore predefinito. L'introduzione di un costruttore fittizio ha fatto scomparire l'errore:

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() {
    }

}

Posso chiederti da dove proviene CustomType. Sto provando una struttura come questa, ma sono assolutamente nuovo a Java.
andho,

181
Puoi usare jackson con classi interne (nidificate), la serializzazione funziona bene in questo caso. L'unico ostacolo è che la classe interna deve essere contrassegnata come "statica" affinché la deserializzazione funzioni correttamente. Vedi l'eslanazione qui: cowtowncoder.com/blog/archives/2010/08/entry_411.html
jpennell,

3
Qualcuno potrebbe spiegare perché questo accade? Ho avuto un errore molto simile. Pensavo che esistessero tutti i costruttori giusti, ma non potevano deserializzare. Ha funzionato solo dopo aver aggiunto un costruttore fittizio, dopo aver letto questo post.
user8658912,

6
@Suman Non lo definirei un costruttore fittizio - è solo il costruttore predefinito. Non solo è perfettamente valido, ma è richiesto per molti tipi di elaborazione di tipo java bean. (E, naturalmente, mi ha fatto inciampare. :-))
fool4jesus

2
Se non si desidera aggiungere un costruttore predefinito (ad esempio, quando si ha a che fare con oggetti immutabili). Dovrai dire quale costruttore o metodo di fabbrica usare per creare un'istanza dell'oggetto usando l'annotazione JsonCreator.
Rahul

376

Questo accade per questi motivi:

  1. la tua classe interna dovrebbe essere definita come statica

    private static class Condition {  //jackson specific    
    }
  2. È possibile che tu non abbia un costruttore predefinito nella tua classe ( AGGIORNAMENTO: questo sembra non essere il caso)

    private static class Condition {
        private Long id;
    
        public Condition() {
        }
    
        // Setters and Getters
    }
  3. È possibile che i setter non siano definiti correttamente o non siano visibili (ad es. Setter privato)


95
la classe statica ha fatto la differenza nel mio caso. Grazie!
jalogar,

3
E, naturalmente, non è necessario dichiarare un costruttore predefinito vuoto, senza argomenti, Java lo fa per te ! (Purché non si definiscano altri costruttori.)
Jonik,

1
@Jonik, giusto! la mia risposta è vecchia, se ricordo bene, dato che Jackson sta usando la riflessione per arrivare alla classe interna, immagino che fosse necessario definire il costruttore predefinito (potrebbe anche non essere un caso nelle versioni più recenti), ma dal momento che non lo sono sicuro che potresti essere corretto.
Azerafati,

6
Sì, la mia esperienza è con Jackson 2.4.4: in effetti il ​​costruttore predefinito implicito di Java è abbastanza. Devi scrivere esplicitamente il costruttore no-args solo se hai definito altri costruttori che accettano argomenti (ovvero quando Java non genera quello no-args per te).
Jonik,

2
Anche con me, la lezione statica ha salvato la giornata.
Simon,

58

Vorrei aggiungere un'altra soluzione a questo che non richiede un costruttore fittizio. Poiché i costruttori fittizi sono un po 'disordinati e successivamente confusi. Siamo in grado di fornire un costruttore sicuro e annotando gli argomenti del costruttore permettiamo a jackson di determinare la mappatura tra parametro del costruttore e campo.

quindi funzionerà anche quanto segue. Nota 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) {
        }

}

Questa soluzione ha funzionato. Voglio solo menzionare quanto segue, avevo un costruttore, ma il nome dei parametri era diverso da quello dei parametri di istanza, quindi non poteva essere mappato. L'aggiunta dell'annotazione ha risolto il problema, ma probabilmente anche la ridenominazione dei parametri avrebbe funzionato.
Fico,

Cosa succede se il parametro del costruttore non è nella risposta? Può essere iniettato in un altro modo?
Eddie Jaoude,

L'unico dato significativo che viene inviato qui è la mela String che è la risposta.
PiersyP,

1
Questo mi è stato utile perché volevo che il mio oggetto fosse immutabile, quindi un costruttore fittizio non era un'opzione.
Jonathan Pullano,

Nel mio caso richiede anche di aggiungere @JsonCreatoril costruttore con @JsonProperty.
m1ld,

31

Quando ho riscontrato questo problema, è stato il risultato del tentativo di utilizzare una classe interna per fungere da DO. La costruzione della classe interna (in silenzio) richiedeva un'istanza della classe chiusa - che non era disponibile per Jackson.

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


6
Mentre lo spostamento della classe interna nel suo file .java funziona, l'aggiunta del modificatore statico risolve anche il problema come indicato nella risposta di @ bludream.
jmarks,

20

Generalmente questo errore si verifica perché non creiamo un costruttore predefinito ma nel mio caso Il problema si presentava solo perché avevo creato una classe di oggetti usata all'interno della classe genitore. Questo ha sprecato la mia intera giornata.


È sufficiente creare la classe nidificata static.
bradipo

13

Thumb Rule : aggiungi un costruttore predefinito per ogni classe che hai usato come classe di mapping. Hai perso questo e il problema si presenta!
Aggiungi semplicemente il costruttore predefinito e dovrebbe funzionare.


bella risposta Grazie per aver salvato la mia giornata.
Steve,

9

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

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

In secondo luogo, aggiungi il costruttore predefinito a ogni classe che potrebbe essere d'aiuto.


Non funzionante: Ottenere il seguente errore: "org.codehaus.jackson.map.exc.UnrecognizedPropertyException: campo non riconosciuto & quot; meleRequest & quot; (Class com.smartshop.dao.AllApplesDO), non contrassegnato come ignorabile"
Lucky Murari

In precedenza non funzionava almeno per errore per AllApplesDO e lanciava solo per la classe chiusa .. ora lancia per la prima classe stessa
Lucky Murari

Necessario un costruttore predefinito. Grazie!
Planky,

questo non dovrebbe essere scelto come risposta CORRETTA?
dente veloce

7

Devi creare un costruttore fittizio vuoto nella nostra classe di modelli, quindi durante la mappatura di json, viene impostato con il metodo setter.


Questa è la soluzione.
David Kobia,

Questo è anche il caso per me. Avevo molti costruttori diversi per il mio oggetto, e quindi ne ho appena creato un altro vuoto che apparentemente viene utilizzato da Jackson.
Alessandro Roaro,

5

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

4

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 usare i costruttori per creare un oggetto ben definito con tutto già impostato.

Quindi, se c'è un costruttore vuoto e ci sono anche setter, usa il costruttore vuoto e i setter. Se non ci sono setter, viene usata della magia oscura (riflessi) per farlo.

Se vuoi usare un costruttore con Jackson, devi usare le annotazioni come menzionato da @PiersyP nella sua risposta. Puoi anche usare un modello di generatore. Se incontri qualche eccezione, buona fortuna. La gestione degli errori a Jackson fa schifo, è difficile capire che è incomprensibile nei messaggi di errore.


Il motivo per cui è necessario un FooClass () predefinito "nessun costruttore di argomenti" è probabilmente perché Spring segue le specifiche JavaBean, che richiedono che funzioni per il marshalling e lo smarhalling automatici durante la serializzazione e la deserializzazione degli oggetti.
atom88,

Bene, la serializzazione e la deserializzazione Java nel flusso binario non sono comunque la questione. Quindi è solo positivo che Jackson offra più schemi da utilizzare con la deserializzazione. Mi piace in particolare il modello del costruttore in quanto consente all'oggetto risultante di essere immutabile.
Vlasec,

3

Per quanto riguarda l'ultima pubblicazione, ho riscontrato lo stesso problema con l'utilizzo di Lombok 1.18. *.

La mia soluzione era quella di aggiungere @NoArgsConstructor (costruttore senza parametri), poiché @Data include per impostazione predefinita @RequiredArgsConstructor (costruttore con parametri).

Documentazione di lombok https://projectlombok.org/features/all

Ciò risolverebbe il problema:

package example.counter;

import javax.validation.constraints.NotNull;

import lombok.Data;

@Data
@NoArgsConstructor
public class CounterRequest {
    @NotNull
    private final Integer int1;

    @NotNull
    private final Integer int2;
}

0

Il problema potrebbe essere anche la mancata serializzazione / deserializzazione di Jackson personalizzati. Anche se non è il tuo caso, vale la pena menzionarlo.

Ho affrontato la stessa eccezione e quello era il caso.


0

Per me, questo funzionava, ma l'aggiornamento delle librerie ha fatto apparire questo problema. Il problema era avere una classe 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 lombok:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.0</version>
</dependency>

Tornando a

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.10</version>
</dependency>

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.