Jackson mit JSON: Nicht erkanntes Feld, nicht als ignorierbar markiert


673

Ich muss eine bestimmte JSON-Zeichenfolge in ein Java-Objekt konvertieren. Ich verwende Jackson für das JSON-Handling. Ich habe keine Kontrolle über die Eingabe JSON (ich lese von einem Webdienst). Dies ist meine Eingabe JSON:

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

Hier ist ein vereinfachter Anwendungsfall:

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

Meine Entitätsklasse ist:

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

Meine Wrapper-Klasse ist im Grunde ein Containerobjekt, um meine Schülerliste abzurufen:

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

Ich erhalte immer wieder diesen Fehler und "Wrapper" kehrt zurück null. Ich bin mir nicht sicher, was fehlt. Kann mir bitte jemand helfen?

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
Ich fand dies nützlich, um das Erstellen einer Wrapper-Klasse zu vermeiden: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});und dannStudent myStudent = dummy.get("wrapper");
pulkitsinghal

6
JSON sollte folgendermaßen aussehen: String jsonStr = "{" student ": [{" id ":" 13 "," name ":" Fred "}]}"; Wenn Sie Wrapper-Objekt in Ihrer REST POST-Anfrage erwarten
Dmitri Algazin

2
Verwandte (aber anders) Frage: Das Ignorieren neue Felder auf JSON - Objekten mit Jackson
sleske

5
Übrigens beantworten die meisten Antworten auf diese Frage tatsächlich eine andere Frage, nämlich eine, die der oben genannten ähnlich ist.
Sleske

4
Die meisten Antworten helfen dabei, das Problem unter den Teppich zu bürsten, anstatt es tatsächlich zu lösen :(
NoobEditor

Antworten:


989

Sie können Jacksons Annotation auf Klassenebene verwenden:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Alle Eigenschaften, die Sie in Ihrem POJO nicht definiert haben, werden ignoriert. Sehr nützlich, wenn Sie nur nach einigen Eigenschaften in JSON suchen und nicht die gesamte Zuordnung schreiben möchten. Weitere Infos auf Jacksons Website . Wenn Sie eine nicht deklarierte Eigenschaft ignorieren möchten, sollten Sie Folgendes schreiben:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, gibt es eine Möglichkeit, dies außerhalb der Klasse zu deklarieren?
Jon Lorusso

4
Ich serialisiere Klassen, die ich nicht besitze (nicht ändern kann). In einer Ansicht möchte ich mit einer bestimmten Reihe von Feldern serialisieren. In einer anderen Ansicht möchte ich einen anderen Satz von Feldern serialisieren (oder die Eigenschaften in JSON umbenennen).
Jon Lorusso

11
Ich muss hinzufügen, dass Sie das brauchen, (ignoreUnknown = true)wenn Sie Ihre Klasse kommentieren, sonst wird es nicht funktionieren
Nekromant

85
Julián, dies ist nicht die richtige Antwort auf die Frage des OP. Ich vermute jedoch, dass Leute hierher kommen, weil sie googeln, wie man Eigenschaften ignoriert, die nicht in POJO definiert sind, und dies ist das erste Ergebnis. Am Ende stimmen sie dies und Sureshs Antwort ab (das ist mir passiert). Obwohl die ursprüngliche Frage nichts damit zu tun hat, undefinierte Eigenschaften ignorieren zu wollen.
Ric Jafe

5
Dies ist eine sehr dumme Standardeinstellung. Wenn Sie Ihrer API eine Eigenschaft hinzufügen, schlägt die gesamte Serialisierung fehl
Headsvk

477

Sie können verwenden

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

Alle nicht deklarierten Eigenschaften werden ignoriert.


5
Dies hat bei mir nicht funktioniert, es scheitert immer noch an unbekannten Eigenschaften
Denis Kniazhev

1
Könnten Sie bitte mindestens einen Teil des Codes einfügen, was genau Sie tun. Möglicherweise haben Sie dort etwas verpasst. Entweder indem Sie dies tun oder "@JsonIgnoreProperties (ignoreUnknown = true)" verwenden. Ihr Problem sollte behoben sein. Sowieso viel Glück.
Suresh

26
FWIW - Ich musste diese etwas andere Aufzählung importieren: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
raf

9
^ Oben ist für Jackson-Versionen vor 2
755

10
Sie können diese Aufrufe auch wie folgt verketten: getObjectMapper (). Disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
icfantv

126

Die erste Antwort ist fast richtig, aber es ist erforderlich, die Getter-Methode zu ändern, NICHT Feld - Feld ist privat (und nicht automatisch erkannt); Außerdem haben Getter Vorrang vor Feldern, wenn beide sichtbar sind. (Es gibt auch Möglichkeiten, private Felder sichtbar zu machen, aber wenn Sie Getter haben möchten, gibt es nicht viel Sinn.)

Daher sollte Getter entweder benannt getWrapper()oder mit folgenden Anmerkungen versehen werden:

@JsonProperty("wrapper")

Wenn Sie den Namen der Getter-Methode so wie sie ist bevorzugen.


Bitte erläutern Sie - welcher Getter muss geändert oder kommentiert werden?
Frans

du meinst mit @JsonGetter ("Wrapper") kommentiert, oder?
Pedram Bashiri

@pedrambashiri Nein, ich meine @JsonProperty. Obwohl @JsonGetteres sich um einen legalen Alias ​​handelt, wird er selten als @JsonPropertyArbeit für Getter, Setter und Felder verwendet. Setter und Getter können durch Signatur unterschieden werden (einer akzeptiert keine Argumente, gibt nicht ungültig zurück; der andere akzeptiert ein Argument).
StaxMan

Dies ist die Antwort, nach der ich gesucht habe! Klingt so, als hätte Jackson Probleme, den Quell-JSON Ihrem POJO zuzuordnen, aber Sie können Übereinstimmungen garantieren, indem Sie die Getter markieren. Vielen Dank!
Andrew Kirna

89

Mit Jackson 2.6.0 funktionierte dies für mich:

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

und mit Einstellung:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Mit dieser Konfiguration ist eine Annotation nicht
erforderlich

Müssen Sie sowohl ObjectMapper als auch Annotation für die Klasse konfigurieren? Ich denke, objectMapper wird für alle Fehler beheben, ohne dass jede Klasse mit Anmerkungen versehen werden muss. Ich benutze die Anmerkung allerdings.
Prayagupd

Sie benötigen nicht beide Einstellungen in derselben Klasse. Sie können DI auch verwenden, um eine globale Singleton-Instanz von abzurufen ObjectMapperund die FAIL_ON_UNKNOWN_PROPERTIESEigenschaft global festzulegen.
user991710

Sie brauchen nicht beide, Sie können das eine oder das andere wählen.
heez

58

Es kann auf zwei Arten erreicht werden:

  1. Markieren Sie das POJO, um unbekannte Eigenschaften zu ignorieren

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Konfigurieren Sie ObjectMapper, der das POJO / json wie folgt serialisiert / de-serialisiert:

    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
Warum sollte dies die akzeptierte Antwort sein? Dies bedeutet lediglich, unbekannte Eigenschaften zu ignorieren, während die Frage darin bestand, einen Weg zu finden, um den JSON in ein Objekt zu verpacken, das in dieser Lösung eindeutig ignoriert werden soll.
Sayantan

42

Das hat bei mir einfach perfekt funktioniert

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

@JsonIgnoreProperties(ignoreUnknown = true) Anmerkung nicht.


2
Abgestimmt, da es die Frage des OP nicht beantwortet. Das Ignorieren unbekannter Eigenschaften löst sein Problem nicht, lässt ihn jedoch mit einer WrapperInstanz zurück, in der die Schülerliste nullleer oder leer ist.
Frans

37

Dies funktioniert besser als alle Bitte beziehen Sie sich auf diese Eigenschaft.

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

Arbeiten wie erwartet!
MADHAIYAN M

Ja, dies ist derjenige, der mein Problem gelöst hat - der zum Titel dieses Beitrags passte.
Scott Langeberg

Die Antworten funktionieren gut für mich und es ist sehr einfach. Danke
Touya Akira

29

Wenn Sie Jackson 2.0 verwenden

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

Warum hat diese Konfiguration keine Auswirkung auf mich?
Zhaozhi

@ Zhaozhi Es hängt von der Jackson-Version ab
Aalkhodiry

20

Laut Dokument können Sie ausgewählte Felder oder alle unbekannten Felder ignorieren:

 // 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

Es hat bei mir mit folgendem Code funktioniert:

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

15

Das Hinzufügen von Setzern und Gettern löste das Problem . Ich war der Meinung, dass das eigentliche Problem darin bestand, wie man es löst, aber nicht, wie man den Fehler unterdrückt / ignoriert. Ich habe den Fehler " Nicht erkanntes Feld .. nicht als ignorierbar markiert .. " erhalten.

Obwohl ich die folgende Annotation über der Klasse verwende, war es nicht möglich, das json-Objekt zu analysieren und mir die Eingabe zu geben

@JsonIgnoreProperties (ignoreUnknown = true)

Dann wurde mir klar, dass ich keine Setter und Getter hinzufügte, nachdem ich dem "Wrapper" und dem "Student" Setter und Getter hinzugefügt hatte, funktionierte es wie ein Zauber.


Dies scheint die einzige Antwort zu sein, die die Frage tatsächlich beantwortet. Alle anderen Antworten markieren nur unbekannte Eigenschaften als ignoriert, aber 'Wrapper' ist keine unbekannte Eigenschaft, sondern das, was wir zu analysieren versuchen.
lbenedetto

14

Jackson beschwert sich, weil er in Ihrer Klasse Wrapper kein Feld finden kann, das "Wrapper" heißt. Dies geschieht, weil Ihr JSON-Objekt eine Eigenschaft namens "Wrapper" hat.

Ich denke, die Lösung besteht darin, das Feld Ihrer Wrapper-Klasse in "Wrapper" anstelle von "Studenten" umzubenennen.


Danke Jim. Ich habe das versucht und es hat das Problem nicht behoben. Ich frage mich, ob mir eine Anmerkung fehlt.
jshree

1
Hmm, was passiert , wenn Sie die entsprechenden Daten in Java erstellen und dann Jackson verwenden , um zu schreiben es in JSON aus. Jeder Unterschied zwischen diesem JSON und dem obigen JSON sollte ein Hinweis darauf sein, was falsch läuft.
Jim Ferrans

Diese Antwort hat bei mir mit dem Beispiel aus der Frage funktioniert.
Sleske

14

Ich habe die folgende Methode ausprobiert und sie funktioniert für das Lesen im JSON-Format mit Jackson. Verwenden Sie die bereits vorgeschlagene Lösung von: annotating getter with@JsonProperty("wrapper")

Deine Wrapper-Klasse

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

Mein Vorschlag für eine Wrapper-Klasse

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")
}

Dies würde Ihnen jedoch die Ausgabe des Formats geben:

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

Weitere Informationen finden Sie unter https://github.com/FasterXML/jackson-annotations

Hoffe das hilft


Willkommen beim Stackoverflow. Tipp: Sie können die {}Symbole in der Symbolleiste verwenden, um Ihre Codefragmente zu formatieren.
Leigh

11

Diese Lösung ist generisch beim Lesen von JSON-Streams und muss nur einige Felder abrufen, während Felder, die in Ihren Domänenklassen nicht korrekt zugeordnet sind, ignoriert werden können:

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

Eine detaillierte Lösung wäre die Verwendung eines Tools wie jsonschema2pojo, um die erforderlichen Domänenklassen wie Student automatisch aus dem Schema der json-Antwort zu generieren. Letzteres können Sie mit jedem Online-Konverter von JSON in Schema ausführen.


10

Kommentieren Sie die Feldschüler wie folgt, da die Namen der Eigenschaften json und java nicht übereinstimmen

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

9

Wie niemand sonst erwähnt hat, dachte ich würde ...

Problem ist, dass Ihre Eigenschaft in Ihrem JSON "Wrapper" heißt und Ihre Eigenschaft in Wrapper.class "Studenten" heißt.

Also entweder...

  1. Korrigieren Sie den Namen der Eigenschaft entweder in der Klasse oder in JSON.
  2. Kommentieren Sie Ihre Eigenschaftsvariable gemäß dem Kommentar von StaxMan.
  3. Kommentieren Sie den Setter (falls Sie einen haben)

6

Setzen Sie Ihre Klassenfelder nicht privat auf öffentlich .

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

2
schlechte Praxis - dies bricht die Kapselung.
Downhillski

1
Das habe ich gehört.
Downhillski

Ihre Klasse ist gefährdet, wenn der Benutzer sie verwendet, da der interne Status durch diese Felder mutiert werden kann.
Downhillski

5

Was für mich funktionierte, war, das Eigentum öffentlich zu machen. Es hat das Problem für mich gelöst.


1
Arbeitete für mich: D
TienLuong

5

Entweder ändern

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

zu

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

---- oder ----

Ändern Sie Ihre JSON-Zeichenfolge in

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

5

Deine Eingabe

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

Gibt an, dass es sich um ein Objekt mit einem Feld namens "Wrapper" handelt, bei dem es sich um eine Sammlung von Schülern handelt. Meine Empfehlung wäre also:

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

wo Wrapperist definiert als

class Wrapper {
    List<Student> wrapper;
}

5

Das neue Firebase Android brachte einige große Änderungen mit sich. unter der Kopie des Dokuments:

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

Aktualisieren Sie Ihre Java-Modellobjekte

Wie beim 2.x SDK konvertiert Firebase Database automatisch Java-Objekte, an die Sie übergeben, DatabaseReference.setValue()in JSON und kann JSON mithilfe von in Java-Objekte lesen DataSnapshot.getValue().

Wenn Sie im neuen SDK JSON in ein Java-Objekt mit lesen DataSnapshot.getValue(), werden unbekannte Eigenschaften im JSON jetzt standardmäßig ignoriert, sodass Sie sie nicht mehr benötigen @JsonIgnoreExtraProperties(ignoreUnknown=true).

Um Felder / Getter beim Schreiben eines Java-Objekts in JSON auszuschließen, wird jetzt die Annotation @Excludeanstelle von aufgerufen @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)

Wenn Ihr JSON eine zusätzliche Eigenschaft enthält, die sich nicht in Ihrer Java-Klasse befindet, wird diese Warnung in den Protokolldateien angezeigt:

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

Sie können diese Warnung entfernen, indem Sie @IgnoreExtraPropertiesIhrer Klasse eine Anmerkung hinzufügen. Wenn Sie möchten, dass sich die Firebase-Datenbank wie im 2.x SDK verhält und eine Ausnahme auslöst, wenn unbekannte Eigenschaften vorhanden sind, können Sie @ThrowOnExtraPropertiesIhrer Klasse eine Anmerkung hinzufügen.


4

Für meinen Teil die einzige Zeile

@JsonIgnoreProperties(ignoreUnknown = true)

hat auch nicht funktioniert.

Einfach hinzufügen

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Das hat bei mir perfekt funktioniert

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Ich habe dieses Problem behoben, indem ich einfach die Signaturen meiner Setter- und Getter-Methoden meiner POJO-Klasse geändert habe. Ich musste lediglich die getObject- Methode so ändern, dass sie dem entspricht , wonach der Mapper suchte. In meinem Fall hatte ich ursprünglich eine getImageUrl , aber die JSON-Daten hatten image_url, was den Mapper abwarf. Ich habe sowohl meinen Setter als auch meinen Getter in getImage_url und setImage_url geändert .

Hoffe das hilft.


Sie haben anscheinend Recht: Wenn der gewünschte Name xxx_yyy lautet, können Sie ihn getXxx_yyy und setXxx_yyy nennen. Das ist sehr seltsam, aber es funktioniert.
Sivi

3

Das POJO sollte definiert sein als

Antwortklasse

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

Wrapper-Klasse

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

und Mapper, um den Wert zu lesen

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

Fast. Nicht wrappersaber wrapper.
Frans

@Frans Haha, danke, dass du den Fehler entdeckt hast. Ich benutze natürlich Plural für eine Sammlung. Aber laut OP-Frage sollte es singulär sein.
Dino Tw

3

Dies kann eine sehr späte Antwort sein, aber nur das Ändern des POJO in dieses sollte die im Problem bereitgestellte JSON-Zeichenfolge lösen (da die Eingabezeichenfolge nicht in Ihrer Kontrolle liegt, wie Sie sagten):

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

3

Eine andere Möglichkeit ist diese Eigenschaft in den application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, für die keine weitere Codeänderung in Ihrer Anwendung erforderlich ist. Und wenn Sie glauben, dass der Vertrag stabil ist, können Sie diese Eigenschaft entfernen oder als wahr markieren.


3

Dies ist möglicherweise nicht das gleiche Problem wie das OP, aber falls jemand mit dem gleichen Fehler wie ich hierher gekommen ist, hilft dies ihm, sein Problem zu lösen. Ich habe den gleichen Fehler wie beim OP erhalten, als ich einen ObjectMapper aus einer anderen Abhängigkeit als die JsonProperty-Annotation verwendet habe.

Das funktioniert:

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

Funktioniert nicht:

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

Vielen Dank! import com.fasterxml.jackson.annotation.JsonProperty arbeitete für mich statt der anderen :-)
phil

2

Google hat mich hierher gebracht und ich war überrascht, die Antworten zu sehen ... alle schlugen vor , den Fehler zu umgehen ( der später in der Entwicklung immer 4-fach zurückbeißt ), anstatt ihn zu lösen, bis dieser Gentleman durch das Vertrauen in SO wiederhergestellt wurde!

objectMapper.readValue(responseBody, TargetClass.class)

wird verwendet, um einen json-String in ein Klassenobjekt zu konvertieren. Was fehlt, ist, dass der TargetClassöffentliche Ter get/ ter haben sollte set. Gleiches fehlt auch im Fragefragment von OP! :) :)

via lombok sollte deine klasse wie unten funktionieren !!

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

2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Vielleicht wären einige weitere Erklärungen oder ein Dokument nett
Benj

@JsonIgnoreProperties (ignoreUnknown = true) funktioniert gut, danke
Guilherme
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.