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)
jshree
la source
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
2
Question connexe (mais différente): ignorer de nouveaux champs sur les objets JSON à l'aide de Jackson
sleske
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)
Ariel Kogan
la source
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.

Suresh
la source
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.

StaxMan
la source
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)
Scott
la source
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) 
Amit Kaneria
la source
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.

Felix Kimutua
la source
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);
2542697
la source
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);
Aalkhodiry
la source
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)
tomrozb
la source
15

Cela a fonctionné pour moi avec le code suivant:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j_bond007
la source
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.

ddc
la source
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".

Jim Ferrans
la source
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

mytwocentsads
la source
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.

George Papatheodorou
la source
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
}
ajith r
la source
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)
TedTrippin
la source
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
}
jamais l'hiver
la source
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.

Rohitesh
la source
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"}]}
Sagar
la source
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;
}
Ran0990BK
la source
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.

ThierryC
la source
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

jodu
la source
4

Cela a parfaitement fonctionné pour moi

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Niamath
la source
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.

superuserdo
la source
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);
Dino Tw
la source
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
}
Sayantan
la source
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.

krmanish007
la source
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
cwa
la source
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;
}
NoobEditor
la source
2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties

Gank
la source
Peut-être que d'autres explications ou doc ​​seraient bien
Benj
@JsonIgnoreProperties (ignoreUnknown = true) fonctionne très bien, merci
Guilherme