Jackson con JSON: campo non riconosciuto, non contrassegnato come ignorabile


677

Devo convertire una determinata stringa JSON in un oggetto Java. Sto usando Jackson per la gestione di JSON. Non ho alcun controllo sull'input JSON (ho letto da un servizio web). Questo è il mio input JSON:

{"wrapper":[{"id":"13","name":"Fred"}]}

Ecco un caso d'uso semplificato:

private void tryReading() {
    String jsonStr = "{\"wrapper\"\:[{\"id\":\"13\",\"name\":\"Fred\"}]}";
    ObjectMapper mapper = new ObjectMapper();  
    Wrapper wrapper = null;
    try {
        wrapper = mapper.readValue(jsonStr , Wrapper.class);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("wrapper = " + wrapper);
}

La mia classe di entità è:

public Class Student { 
    private String name;
    private String id;
    //getters & setters for name & id here
}

La mia classe Wrapper è fondamentalmente un oggetto contenitore per ottenere il mio elenco di studenti:

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

Continuo a ricevere questo errore e restituisce "wrapper" null. Non sono sicuro di cosa manchi. Qualcuno può aiutare per favore?

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: 
    Unrecognized field "wrapper" (Class Wrapper), not marked as ignorable
 at [Source: java.io.StringReader@1198891; line: 1, column: 13] 
    (through reference chain: Wrapper["wrapper"])
 at org.codehaus.jackson.map.exc.UnrecognizedPropertyException
    .from(UnrecognizedPropertyException.java:53)

2
L'ho trovato utile per evitare di creare una classe wrapper: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});e poiStudent myStudent = dummy.get("wrapper");
pulkitsinghal,

6
JSON dovrebbe apparire come: String jsonStr = "{\" students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; se ti aspetti l'oggetto Wrapper nella tua richiesta POST REST
Dmitri Algazin


5
E per inciso, la maggior parte delle risposte a questa domanda in realtà risponde a una domanda diversa, vale a dire una simile a quella che ho descritto sopra.
sleske,

4
la maggior parte delle risposte aiuta a risolvere il problema sotto il tappeto anziché risolverlo effettivamente :(
NoobEditor,

Risposte:


992

Puoi usare l'annotazione a livello di classe di Jackson:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Ignorerà tutte le proprietà che non sono state definite nel POJO. Molto utile quando stai solo cercando un paio di proprietà in JSON e non vuoi scrivere l'intera mappatura. Maggiori informazioni sul sito Web di Jackson . Se si desidera ignorare qualsiasi proprietà non dichiarata, è necessario scrivere:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, c'è un modo per dichiararlo esterno alla classe?
Jon Lorusso,

4
Sto serializzando le classi che non possiedo (non posso modificare). In una vista, vorrei serializzare con un certo set di campi. In un'altra vista, voglio un diverso set di campi serializzati (o forse rinominare le proprietà in JSON).
Jon Lorusso,

11
devo aggiungere che ti serve (ignoreUnknown = true)quando annoti la lezione, altrimenti non funzionerà
Negromante

85
Julián, questa non è la risposta corretta alla domanda del PO. Tuttavia, sospetto che le persone vengano qui perché usano Google per ignorare le proprietà non definite in POJO e questo è il primo risultato, quindi finiscono per votare questo e la risposta di Suresh (ecco cosa mi è successo). Sebbene la domanda originale non abbia nulla a che fare con il voler ignorare le proprietà non definite.
Ric Jafe,

5
questa è un'impostazione predefinita molto stupida, se aggiungi una proprietà al tuo api, l'intera serializzazione fallisce
headsvk

481

Puoi usare

ObjectMapper objectMapper = getObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Ignorerà tutte le proprietà che non sono state dichiarate.


5
Questo non ha funzionato per me, fallisce ancora su proprietà sconosciute
Denis Kniazhev,

1
Potresti per favore incollare almeno un pezzo di codice esattamente quello che stai facendo, potresti esserti perso qualcosa lì .. O facendo questo o usando "@JsonIgnoreProperties (ignoreUnnown = true)" Il tuo problema dovrebbe essere risolto. Comunque buona fortuna.
Suresh,

27
FWIW - Ho dovuto importare questo enum leggermente diverso: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
raf

9
^ Sopra è per Jackson versioni precedenti a 2
755

10
Puoi anche concatenare queste chiamate come: getObjectMapper ().
Disable

126

La prima risposta è quasi corretta, ma è necessario cambiare il metodo getter, NON il campo: il campo è privato (e non rilevato automaticamente); inoltre, i getter hanno la precedenza sui campi se entrambi sono visibili (ci sono anche modi per rendere visibili i campi privati, ma se si desidera avere il getter non ha molto senso)

Quindi getter dovrebbe essere nominato getWrapper()o annotato con:

@JsonProperty("wrapper")

Se si preferisce il nome del metodo getter così com'è.


Si prega di elaborare: quale getter deve essere modificato o annotato?
Frans,

vuoi dire annotato con @JsonGetter ("wrapper"), giusto?
Pedram Bashiri,

@pedrambashiri No, intendo @JsonProperty. Sebbene @JsonGettersia un alias legale, viene raramente utilizzato come @JsonPropertylavoro per getter, setter e campi; setter e getter possono essere distinti per firma (uno non accetta argomenti, restituisce un valore nullo; l'altro accetta un argomento).
StaxMan

Questa è la risposta che stavo cercando! Sembra che Jackson abbia problemi a mappare la sorgente JSON sul POJO, ma puoi garantire le partite taggando i getter. Grazie!
Andrew Kirna,

90

usando Jackson 2.6.0, ha funzionato per me:

private static final ObjectMapper objectMapper = 
    new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

e con impostazione:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Con quella configurazione l'annotazione non è necessaria
neworld

Devi configurare sia ObjectMapper che Annotation sulla classe? Immagino che objectMapper risolverà per tutti, senza la necessità di annotare ogni classe. Uso l'annotazione però.
prayagupd,

Non sono necessarie entrambe le impostazioni nella stessa classe. È inoltre possibile utilizzare DI per ottenere un'istanza singleton globale di ObjectMapper, per impostare la FAIL_ON_UNKNOWN_PROPERTIESproprietà a livello globale.
user991710

Non hai bisogno di entrambi, puoi scegliere l'uno o l'altro.
Heez,

58

può essere raggiunto in 2 modi:

  1. Contrassegna il POJO per ignorare le proprietà sconosciute

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Configurare ObjectMapper che serializza / deserializza POJO / json come di seguito:

    ObjectMapper mapper =new ObjectMapper();            
    // for Jackson version 1.X        
    mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    // for Jackson version 2.X
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 

2
Perché questa dovrebbe essere la risposta accettata? Questo dice solo di ignorare le proprietà sconosciute, mentre la domanda era trovare un modo per ottenere il json avvolto in un oggetto che questa soluzione dice chiaramente di ignorare.
Sayantan,

42

Questo ha funzionato perfettamente per me

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(
    DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

@JsonIgnoreProperties(ignoreUnknown = true) l'annotazione no.


2
Sottovalutato in quanto non risponde alla domanda del PO. Ignorare proprietà sconosciute non risolve il suo problema, ma lo lascia con Wrapperun'istanza in cui l'elenco degli studenti è nullo vuoto.
Frans,

37

Funziona meglio di Tutti, fai riferimento a questa proprietà.

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    projectVO = objectMapper.readValue(yourjsonstring, Test.class);

Funzionando come previsto!
MADHAIYAN M,

Sì, questo è quello che ha risolto il mio problema - che corrispondeva al titolo di questo post.
Scott Langeberg,

Le risposte funzionano bene per me ed è molto semplice. Grazie
Touya Akira,

29

Se stai usando Jackson 2.0

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

perché questa configurazione non ha alcun effetto per me?
Zhaozhi,

@zhaozhi Dipende dalla versione di Jackson
Aalkhodiry,

20

Secondo il documento è possibile ignorare i campi selezionati o tutti i campi noti:

 // to prevent specified fields from being serialized or deserialized
 // (i.e. not include in JSON output; or being set even if they were included)
 @JsonIgnoreProperties({ "internalId", "secretKey" })

 // To ignore any unknown properties in JSON input without exception:
 @JsonIgnoreProperties(ignoreUnknown=true)

15

Ha funzionato per me con il seguente codice:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

15

L'aggiunta di setter e getter ha risolto il problema , quello che ho sentito è il vero problema era come risolverlo ma non come sopprimere / ignorare l'errore. Ho ricevuto l'errore " Campo non riconosciuto .. non contrassegnato come ignorabile .. "

Sebbene io usi l'annotazione sotto in cima alla classe, non è stato in grado di analizzare l'oggetto JSON e darmi l'input

@JsonIgnoreProperties (ignoreUnknown = true)

Poi mi sono reso conto che non ho aggiunto setter e getter, dopo aver aggiunto setter e getter al "Wrapper" e allo "Studente" ha funzionato come un incantesimo.


Questa sembra essere l'unica risposta che risponde effettivamente alla domanda. Tutte le altre risposte stanno semplicemente contrassegnando le proprietà sconosciute come ignorate, ma "wrapper" non è una proprietà sconosciuta, è ciò che stiamo cercando di analizzare.
lbenedetto,

14

Jackson si lamenta perché non riesce a trovare un campo nella tua classe Wrapper che si chiama "wrapper". Lo sta facendo perché il tuo oggetto JSON ha una proprietà chiamata "wrapper".

Penso che la soluzione sia quella di rinominare il campo della classe Wrapper in "wrapper" anziché "studenti".


Grazie Jim. L'ho provato e non ha risolto il problema. Mi chiedo se mi manca qualche annotazione ..
jshree

1
Cosa succede quando si creano i dati equivalenti in Java e poi si usa Jackson per scriverli in JSON. Qualsiasi differenza tra quel JSON e il JSON sopra dovrebbe essere un indizio di cosa non va.
Jim Ferrans,

Questa risposta ha funzionato per me, con l'esempio della domanda.
sleske,

14

Ho provato il metodo seguente e funziona con tale lettura del formato JSON con Jackson. Usa la soluzione già suggerita di: annotare getter con@JsonProperty("wrapper")

La tua classe wrapper

public Class Wrapper{ 
  private List<Student> students;
  //getters & setters here 
} 

Il mio suggerimento per la classe wrapper

public Class Wrapper{ 

  private StudentHelper students; 

  //getters & setters here 
  // Annotate getter
  @JsonProperty("wrapper")
  StudentHelper getStudents() {
    return students;
  }  
} 


public class StudentHelper {

  @JsonProperty("Student")
  public List<Student> students; 

  //CTOR, getters and setters
  //NOTE: If students is private annotate getter with the annotation @JsonProperty("Student")
}

Questo ti darebbe comunque l'output del formato:

{"wrapper":{"student":[{"id":13,"name":Fred}]}}

Inoltre per ulteriori informazioni consultare https://github.com/FasterXML/jackson-annotations

Spero che sia di aiuto


Benvenuto in StackOverflow. Suggerimento, puoi utilizzare i {}simboli nella barra degli strumenti per formattare i frammenti di codice.
Leigh,

11

Questa soluzione è generica quando si leggono flussi json e è necessario ottenere solo alcuni campi mentre i campi non mappati correttamente nelle classi di dominio possono essere ignorati:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)

Una soluzione dettagliata sarebbe quella di utilizzare uno strumento come jsonschema2pojo per generare automaticamente le classi di dominio richieste come Studente dallo schema della risposta json. Puoi fare quest'ultimo da qualsiasi convertitore online da json a schema.


10

Annota gli studenti sul campo come di seguito poiché non vi è corrispondenza tra i nomi di proprietà json e proprietà java

public Class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;
    //getters & setters here
}

9

Come nessun altro ha menzionato, ho pensato che avrei ...

Il problema è che la tua proprietà nel tuo JSON si chiama "wrapper" e la tua proprietà in Wrapper.class si chiama "studenti".

Quindi o ...

  1. Correggere il nome della proprietà nella classe o JSON.
  2. Annota la tua variabile di proprietà secondo il commento di StaxMan.
  3. Annota il setter (se ne hai uno)

6

rendere pubblici i campi della classe non privati .

public Class Student { 
    public String name;
    public String id;
    //getters & setters for name & id here
}

2
cattiva pratica - questo rompe l'incapsulamento.
Downhillski,

1
L'ho sentito.
Downhillski,

La tua classe è a rischio quando l'utente la utilizza perché lo stato interno potrebbe essere mutato attraverso questi campi.
Downhillski,

5

Ciò che ha funzionato per me è stato rendere pubblica la proprietà. Mi ha risolto il problema.


1
Ha funzionato per me: D
TienLuong

5

O cambia

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

per

public Class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

---- o ----

Cambia la tua stringa JSON in

{"students":[{"id":"13","name":"Fred"}]}

5

Il tuo input

{"wrapper":[{"id":"13","name":"Fred"}]}

indica che si tratta di un oggetto, con un campo denominato "wrapper", che è una raccolta di studenti. Quindi la mia raccomandazione sarebbe

Wrapper = mapper.readValue(jsonStr , Wrapper.class);

dove Wrapperè definito come

class Wrapper {
    List<Student> wrapper;
}

5

Il nuovo Android Firebase ha introdotto alcuni enormi cambiamenti; sotto la copia del documento:

[ https://firebase.google.com/support/guides/firebase-android] :

Aggiorna gli oggetti del tuo modello Java

Come con l'SDK 2.x, Firebase Database converte automaticamente gli oggetti Java a cui si passa DatabaseReference.setValue()in JSON e può leggere JSON in oggetti Java utilizzando DataSnapshot.getValue().

Nel nuovo SDK, quando si legge JSON in un oggetto Java con DataSnapshot.getValue(), le proprietà sconosciute in JSON vengono ora ignorate per impostazione predefinita, quindi non è più necessario @JsonIgnoreExtraProperties(ignoreUnknown=true).

Per escludere campi / getter quando si scrive un oggetto Java su JSON, l'annotazione viene ora chiamata @Excludeinvece di @JsonIgnore.

BEFORE

@JsonIgnoreExtraProperties(ignoreUnknown=true)
public class ChatMessage {
   public String name;
   public String message;
   @JsonIgnore
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

AFTER

public class ChatMessage {
   public String name;
   public String message;
   @Exclude
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

Se nel JSON è presente una proprietà aggiuntiva che non appartiene alla classe Java, verrà visualizzato questo avviso nei file di registro:

W/ClassMapper: No setter/field for ignoreThisProperty found on class com.firebase.migrationguide.ChatMessage

Puoi eliminare questo avviso inserendo @IgnoreExtraPropertiesun'annotazione nella tua classe. Se desideri che Firebase Database si comporti come nell'SDK 2.x e generi un'eccezione se ci sono proprietà sconosciute, puoi inserire @ThrowOnExtraPropertiesun'annotazione nella tua classe.


4

Da parte mia, l'unica riga

@JsonIgnoreProperties(ignoreUnknown = true)

non ha funzionato troppo.

Aggiungi

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Ha funzionato perfettamente per me

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Ho risolto questo problema semplicemente cambiando le firme del mio setter e dei metodi getter della mia classe POJO. Tutto quello che dovevo fare era cambiare il metodo getObject in modo che corrispondesse a ciò che il mapper stava cercando. Nel mio caso avevo originariamente un getImageUrl , ma i dati JSON avevano image_url che stava gettando via il mapper. Ho cambiato sia il mio setter che i getter in getImage_url e setImage_url .

Spero che sia di aiuto.


apparentemente hai ragione: se il nome che vuoi è xxx_yyy Il modo per chiamarlo sarebbe getXxx_yyy e setXxx_yyy. Questo è molto strano ma funziona.
sivi,

3

Il POJO dovrebbe essere definito come

Classe di risposta

public class Response {
    private List<Wrapper> wrappers;
    // getter and setter
}

Classe wrapper

public class Wrapper {
    private String id;
    private String name;
    // getters and setters
}

e mapper per leggere il valore

Response response = mapper.readValue(jsonStr , Response.class);

Quasi. No wrappers, ma wrapper.
Frans,

@Frans Haha, grazie per aver colto l'errore. Uso naturalmente il plurale per una collezione. Ma per la domanda di OP, dovrebbe essere singolare.
Dino Tw,

3

Questa potrebbe essere una risposta molto tardiva, ma la semplice modifica del POJO in questo dovrebbe risolvere la stringa json fornita nel problema (poiché la stringa di input non è sotto il tuo controllo come hai detto):

public class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

3

Un'altra possibilità è questa proprietà in application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, che non richiede altre modifiche al codice nell'applicazione. E quando ritieni che il contratto sia stabile, puoi rimuovere questa proprietà o contrassegnarla come vera.


3

Questo potrebbe non essere lo stesso problema dell'OP, ma nel caso in cui qualcuno sia arrivato qui con lo stesso errore che ho avuto, questo li aiuterà a risolvere il loro problema. Ho avuto lo stesso errore dell'OP quando ho usato un ObjectMapper da una dipendenza diversa dall'annotazione JsonProperty.

Questo funziona:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonProperty;

Non funziona:

import org.codehaus.jackson.map.ObjectMapper; //org.codehaus.jackson:jackson-mapper-asl:1.8.8
import com.fasterxml.jackson.annotation.JsonProperty; //com.fasterxml.jackson.core:jackson-databind:2.2.3

Grazie! import com.fasterxml.jackson.annotation.JsonProperty ha funzionato per me invece per l'altro :-)
phil

2

Google mi ha portato qui e sono stato sorpreso di vedere le risposte ... tutti hanno suggerito di bypassare l'errore ( che morde sempre 4 volte più tardi nello sviluppo ) piuttosto che risolverlo fino a quando questo gentiluomo ripristinato dalla fede in SO!

objectMapper.readValue(responseBody, TargetClass.class)

viene utilizzato per convertire una stringa json in un oggetto di classe, ciò che manca è che TargetClassdovrebbero avere i getter ter pubblici set. Lo stesso manca anche nello snippet di domande di OP! :)

via lombok la tua classe come sotto dovrebbe funzionare !!

@Data
@Builder
public class TargetClass {
    private String a;
}

2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Forse alcune ulteriori spiegazioni o documenti sarebbero carini
Benj,

@JsonIgnoreProperties (ignoreUnknown = true) funziona bene, grazie
Guilherme,
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.