Jackson avec JSON: champ non reconnu, non marqué comme ignorable


677

J'ai besoin de convertir une certaine chaîne JSON en un objet Java. J'utilise Jackson pour la gestion JSON. Je n'ai aucun contrôle sur le JSON d'entrée (j'ai lu à partir d'un service Web). Voici mon entrée JSON:

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

Voici un cas d'utilisation simplifié:

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

Ma classe d'entité est:

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

Ma classe Wrapper est essentiellement un objet conteneur pour obtenir ma liste d'étudiants:

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

Je continue à recevoir cette erreur et les retours "wrapper" null. Je ne sais pas ce qui manque. Quelqu'un peut-il aider s'il vous plaît?

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
J'ai trouvé cela utile pour éviter de créer une classe wrapper: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});puisStudent myStudent = dummy.get("wrapper");
pulkitsinghal

6
JSON devrait ressembler à: String jsonStr = "{\" students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; si vous attendez un objet Wrapper dans votre demande REST POST
Dmitri Algazin


5
Et accessoirement, la plupart des réponses à cette question répondent en fait à une autre question, à savoir une similaire à celle que je lie ci-dessus.
sleske

4
la majorité des réponses permettent de résoudre le problème sous le tapis plutôt que de le résoudre :(
NoobEditor

Réponses:


992

Vous pouvez utiliser l'annotation de niveau classe de Jackson:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Il ignorera toutes les propriétés que vous n'avez pas définies dans votre POJO. Très utile lorsque vous recherchez simplement quelques propriétés dans le JSON et que vous ne souhaitez pas écrire l'intégralité du mappage. Plus d'informations sur le site Web de Jackson . Si vous souhaitez ignorer toute propriété non déclarée, vous devez écrire:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, existe-t-il un moyen de déclarer cela externe à la classe?
Jon Lorusso

4
Je sérialise des classes que je ne possède pas (ne peut pas modifier). Dans une vue, je voudrais sérialiser avec un certain ensemble de champs. Dans une autre vue, je veux un ensemble différent de champs sérialisés (ou peut-être renommer les propriétés dans le JSON).
Jon Lorusso

11
je dois ajouter que vous avez besoin de l' (ignoreUnknown = true)annotation de votre classe sinon cela ne fonctionnera pas
nécromancien

85
Julián, ce n'est pas la bonne réponse à la question du PO. Cependant, je soupçonne que les gens viennent ici parce qu'ils google comment ignorer les propriétés non définies dans POJO et c'est le premier résultat, alors ils finissent par voter et la réponse de Suresh (c'est ce qui m'est arrivé). Bien que la question d'origine n'ait rien à voir avec le fait d'ignorer les propriétés non définies.
Ric Jafe

5
il s'agit d'un paramètre par défaut très stupide à mon humble avis, si vous ajoutez une propriété à votre API, toute la sérialisation échoue
headsvk

481

Vous pouvez utiliser

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

Il ignorera toutes les propriétés non déclarées.


5
Cela n'a pas fonctionné pour moi, il échoue toujours sur des propriétés inconnues
Denis Kniazhev

1
Pourriez-vous s'il vous plaît coller au moins un morceau de code exactement ce que vous faites? Quoi qu'il en soit bonne chance.
Suresh

27
FWIW - J'ai dû importer cette énumération légèrement différente: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNknown_PROPERTIES
raf

9
^ Ci-dessus est pour les versions Jackson antérieures au 2
755

10
Vous pouvez également chaîner ces appels comme: getObjectMapper (). Disable (DeserializationFeature.FAIL_ON_UNknown_PROPERTIES)
icfantv

126

La première réponse est presque correcte, mais ce qu'il faut, c'est changer la méthode getter, PAS le champ - le champ est privé (et non auto-détecté); en outre, les getters ont priorité sur les champs si les deux sont visibles (il existe des moyens de rendre les champs privés visibles également, mais si vous voulez avoir un getter, il n'y a pas grand-chose à voir)

Donc, getter doit être nommé getWrapper()ou annoté avec:

@JsonProperty("wrapper")

Si vous préférez le nom de la méthode getter tel quel.


Veuillez préciser - quel getter doit être modifié ou annoté?
Frans

vous voulez dire annoté avec @JsonGetter ("wrapper"), non?
pedram bashiri

@pedrambashiri Non, je veux dire @JsonProperty. Bien @JsonGetterqu'il s'agisse d'un alias légal, il est rarement utilisé comme @JsonPropertytravaux pour les getters, les setters et les champs; les setters et les getters peuvent être distingués par la signature (l'un ne prend aucun argument, retourne non nul; l'autre prend un argument).
StaxMan

C'est la réponse que je cherchais! On dirait que Jackson a du mal à mapper le JSON source à votre POJO, mais vous pouvez garantir des correspondances en marquant les getters. Merci!
Andrew Kirna

90

en utilisant Jackson 2.6.0, cela a fonctionné pour moi:

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

et avec réglage:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Avec cette config, l'annotation n'est pas nécessaire
neworld

Avez-vous besoin de configurer ObjectMapper et Annotation sur la classe? Je suppose que objectMapper corrigera pour tous, sans avoir besoin d'annoter chaque classe. J'utilise cependant l'annotation.
Prayagupd

Vous n'avez pas besoin des deux paramètres dans la même classe. Vous pouvez également utiliser DI pour obtenir une instance singleton globale de ObjectMapper, pour définir la FAIL_ON_UNKNOWN_PROPERTIESpropriété globalement.
user991710

Vous n'avez pas besoin des deux, vous pouvez choisir l'un ou l'autre.
heez

58

il peut être réalisé de 2 manières:

  1. Marquez le POJO pour ignorer les propriétés inconnues

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Configurez ObjectMapper qui sérialise / désérialise le POJO / json comme ci-dessous:

    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
Pourquoi devrait-ce être la réponse acceptée? Cela indique simplement d'ignorer les propriétés inconnues, alors que la question était de trouver un moyen d'envelopper le json dans un objet que cette solution dit clairement d'ignorer.
Sayantan

42

Cela a parfaitement fonctionné pour moi

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

@JsonIgnoreProperties(ignoreUnknown = true) l'annotation ne l'a pas fait.


2
Voté car il ne répond pas à la question du PO. Ignorer les propriétés inconnues ne résout pas son problème, mais lui laisse une Wrapperinstance où la liste des étudiants est nullou vide.
Frans

37

Cela fonctionne mieux que tous s'il vous plaît se référer à cette propriété.

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

Fonctionne comme prévu!
MADHAIYAN M

Oui, c'est celui qui a résolu mon problème - qui correspondait au titre de cet article.
Scott Langeberg

Les réponses fonctionnent bien pour moi et c'est très facile. Merci
Touya Akira

29

Si vous utilisez Jackson 2.0

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

pourquoi cette config n'a aucun effet pour moi?
zhaozhi

@zhaozhi Cela dépend de la version de Jackson
Aalkhodiry

20

Selon le document, vous pouvez ignorer les champs sélectionnés ou tous les champs inconnus:

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

Cela a fonctionné pour moi avec le code suivant:

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

15

L'ajout de setters et de getters a résolu le problème , ce que je pensais être le vrai problème était de savoir comment le résoudre mais pas comment supprimer / ignorer l'erreur. J'ai eu l'erreur " Champ non reconnu .. non marqué comme ignorable .. "

Bien que j'utilise l'annotation ci-dessous en haut de la classe, il n'a pas pu analyser l'objet json et me donner l'entrée

@JsonIgnoreProperties (ignoreUnknown = true)

Puis j'ai réalisé que je n'ai pas ajouté de setters et de getters, après avoir ajouté des setters et des getters au "Wrapper" et au "Student" cela a fonctionné comme un charme.


Cela semble être la seule réponse qui répond réellement à la question. Toutes les autres réponses marquent simplement les propriétés inconnues comme ignorées, mais «wrapper» n'est pas une propriété inconnue, c'est ce que nous essayons d'analyser.
lbenedetto

14

Jackson se plaint car il ne trouve pas de champ dans votre classe Wrapper appelé "wrapper". C'est parce que votre objet JSON a une propriété appelée "wrapper".

Je pense que le correctif consiste à renommer le champ de votre classe Wrapper en "wrapper" au lieu de "étudiants".


Merci Jim. J'ai essayé et cela n'a pas résolu le problème. Je me demande s'il me manque une annotation ..
jshree

1
Hmm, que se passe-t-il lorsque vous créez les données équivalentes en Java, puis utilisez Jackson pour les écrire en JSON. Toute différence entre ce JSON et le JSON ci-dessus devrait être un indice de ce qui ne va pas.
Jim Ferrans

Cette réponse a fonctionné pour moi, avec l'exemple de la question.
sleske

14

J'ai essayé la méthode ci-dessous et cela fonctionne pour une telle lecture au format JSON avec Jackson. Utilisez la solution déjà suggérée de: annoter getter avec@JsonProperty("wrapper")

Votre classe wrapper

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

Ma suggestion de 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")
}

Cela vous donnerait cependant la sortie du format:

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

Pour plus d'informations, reportez-vous également à https://github.com/FasterXML/jackson-annotations

J'espère que cela t'aides


Bienvenue sur stackoverflow. Astuce, vous pouvez utiliser les {}symboles de la barre d'outils pour formater vos extraits de code.
Leigh

11

Cette solution est générique lors de la lecture de flux json et n'a besoin d'obtenir que certains champs alors que les champs non mappés correctement dans vos classes de domaine peuvent être ignorés:

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

Une solution détaillée serait d'utiliser un outil tel que jsonschema2pojo pour générer automatiquement les classes de domaine requises telles que Student à partir du schéma de la réponse json. Vous pouvez le faire par n'importe quel convertisseur json en schéma en ligne.


10

Annotez les étudiants sur le terrain comme ci-dessous car il y a un décalage dans les noms des propriétés json et java

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

9

Comme personne d'autre ne l'a mentionné, j'ai pensé que je le ferais ...

Le problème est que votre propriété dans votre JSON est appelée "wrapper" et votre propriété dans Wrapper.class est appelée "étudiants".

Alors non plus ...

  1. Corrigez le nom de la propriété dans la classe ou JSON.
  2. Annotez votre variable de propriété selon le commentaire de StaxMan.
  3. Annoter le setter (si vous en avez un)

6

rendre public vos champs de classe non privés .

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

2
mauvaise pratique - cela rompt l'encapsulation.
Downhillski

1
J'ai entendu dire que.
Downhillski

Votre classe est en danger lorsque l'utilisateur l'utilise car l'état interne peut être modifié par ces champs.
Downhillski

5

Ce qui a fonctionné pour moi, c'est de rendre la propriété publique. Cela a résolu le problème pour moi.


1
A travaillé pour moi: D
TienLuong

5

Soit changer

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

à

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

---- ou ----

Changez votre chaîne JSON en

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

5

Votre contribution

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

indique qu'il s'agit d'un objet, avec un champ nommé "wrapper", qui est une collection d'étudiants. Donc, ma recommandation serait,

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

Wrapperest défini comme

class Wrapper {
    List<Student> wrapper;
}

5

Le nouveau Firebase Android a introduit d'énormes changements; ci-dessous la copie du document:

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

Mettez à jour vos objets de modèle Java

Comme avec le SDK 2.x, la base de données Firebase convertira automatiquement les objets Java que vous passez DatabaseReference.setValue()en JSON et peut lire JSON en objets Java à l'aide DataSnapshot.getValue().

Dans le nouveau SDK, lors de la lecture de JSON dans un objet Java avec DataSnapshot.getValue(), les propriétés inconnues dans le JSON sont désormais ignorées par défaut, vous n'avez donc plus besoin @JsonIgnoreExtraProperties(ignoreUnknown=true).

Pour exclure des champs / getters lors de l'écriture d'un objet Java dans JSON, l'annotation est désormais appelée à la @Excludeplace de @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)

S'il existe une propriété supplémentaire dans votre JSON qui n'est pas dans votre classe Java, vous verrez cet avertissement dans les fichiers journaux:

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

Vous pouvez vous débarrasser de cet avertissement en mettant une @IgnoreExtraPropertiesannotation sur votre classe. Si vous souhaitez que la base de données Firebase se comporte comme dans le SDK 2.x et lève une exception s'il existe des propriétés inconnues, vous pouvez mettre une @ThrowOnExtraPropertiesannotation sur votre classe.


4

Pour ma part, la seule ligne

@JsonIgnoreProperties(ignoreUnknown = true)

n'a pas fonctionné aussi.

Ajoutez simplement

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Cela a parfaitement fonctionné pour moi

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

J'ai résolu ce problème en changeant simplement les signatures de mes méthodes setter et getter de ma classe POJO. Tout ce que j'avais à faire était de changer la méthode getObject pour qu'elle corresponde à ce que le mappeur recherchait. Dans mon cas, j'avais à l' origine un getImageUrl , mais les données JSON avaient image_url qui rejetait le mappeur. J'ai changé à la fois mon setter et mes getters en getImage_url et setImage_url .

J'espère que cela t'aides.


vous avez apparemment raison: si le nom que vous voulez est xxx_yyy La façon de l'appeler serait getXxx_yyy et setXxx_yyy. C'est très étrange mais ça marche.
sivi

3

Le POJO doit être défini comme

Classe de réponse

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

Classe Wrapper

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

et mappeur pour lire la valeur

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

Presque. Non wrappers, mais wrapper.
Frans

@Frans Haha, merci d'avoir rattrapé l'erreur. J'utilise naturellement le pluriel pour une collection. Mais selon la question du PO, cela devrait être singulier.
Dino Tw

3

Cela peut être une réponse très tardive, mais le simple fait de changer le POJO en ceci devrait résoudre la chaîne json fournie dans le problème (car la chaîne d'entrée n'est pas sous votre contrôle comme vous l'avez dit):

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

3

Une autre possibilité est cette propriété dans le fichier application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, qui ne nécessitera aucun autre changement de code dans votre application. Et lorsque vous pensez que le contrat est stable, vous pouvez supprimer cette propriété ou la marquer comme vraie.


3

Ce n'est peut-être pas le même problème que le PO, mais au cas où quelqu'un arriverait avec la même erreur que moi, cela les aiderait à résoudre leur problème. J'ai eu la même erreur que l'OP lorsque j'ai utilisé un ObjectMapper d'une dépendance différente comme l'annotation JsonProperty.

Cela marche:

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

Ne marche pas:

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

Merci! import com.fasterxml.jackson.annotation.JsonProperty a fonctionné pour moi à la place de l'autre :-)
phil

2

Google m'a amené ici et j'ai été surpris de voir les réponses ... tous ont suggéré de contourner l'erreur ( qui mord toujours 4 fois plus tard dans le développement ) plutôt que de la résoudre jusqu'à ce que ce monsieur soit restauré par la foi en SO!

objectMapper.readValue(responseBody, TargetClass.class)

est utilisé pour convertir une chaîne json en un objet de classe, ce qui manque, c'est que le TargetClassdevrait avoir des getter / setters publics . Il en va de même dans l'extrait de question d'OP! :)

via lombok votre classe comme ci-dessous devrait fonctionner !!

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

2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Peut-être que d'autres explications ou doc ​​seraient bien
Benj

@JsonIgnoreProperties (ignoreUnknown = true) fonctionne très bien, merci
Guilherme
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.