Jackson con JSON: campo no reconocido, no marcado como ignorable


677

Necesito convertir una determinada cadena JSON en un objeto Java. Estoy usando Jackson para el manejo de JSON. No tengo control sobre la entrada JSON (leí desde un servicio web). Esta es mi entrada JSON:

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

Aquí hay un caso de uso simplificado:

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

Mi clase de entidad es:

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

Mi clase Wrapper es básicamente un objeto contenedor para obtener mi lista de estudiantes:

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

Sigo recibiendo este error y vuelve el "contenedor" null. No estoy seguro de lo que falta. ¿Puede alguien ayudar, por favor?

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
Encontré esto útil para evitar crear una clase de contenedor: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});y luegoStudent myStudent = dummy.get("wrapper");
pulkitsinghal

66
JSON debería verse así: String jsonStr = "{\" students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; si espera un objeto Wrapper en su solicitud REST POST
Dmitri Algazin

2
Pregunta relacionada (pero diferente): Ignorar nuevos campos en objetos JSON usando Jackson
sleske

55
Y, por cierto, la mayoría de las respuestas a esta pregunta en realidad responden una pregunta diferente, es decir, una similar a la que menciono anteriormente.
sleske

44
La mayoría de las respuestas ayudan a cepillar el problema debajo de la alfombra en lugar de resolverlo :(
NoobEditor

Respuestas:


992

Puede usar la anotación de nivel de clase de Jackson:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Ignorará todas las propiedades que no haya definido en su POJO. Muy útil cuando solo busca un par de propiedades en el JSON y no desea escribir toda la asignación. Más información en el sitio web de Jackson . Si desea ignorar cualquier propiedad no declarada, debe escribir:

@JsonIgnoreProperties(ignoreUnknown = true)

99
Ariel, ¿hay alguna forma de declarar esto externo a la clase?
Jon Lorusso el

44
Estoy serializando clases que no me pertenecen (no puedo modificar). En una vista, me gustaría serializar con un cierto conjunto de campos. En otra vista, quiero un conjunto diferente de campos serializados (o tal vez cambiar el nombre de las propiedades en el JSON).
Jon Lorusso

11
Debo agregar que necesitas (ignoreUnknown = true)cuando anotas tu clase, de lo contrario no funcionará
nigromante

85
Julián, esta no es la respuesta correcta a la pregunta del OP. Sin embargo, sospecho que las personas vienen aquí porque buscan en Google cómo ignorar propiedades no definidas en POJO y este es el primer resultado, por lo que terminan votando esto y la respuesta de Suresh (eso es lo que me pasó a mí). Aunque la pregunta original no tiene nada que ver con querer ignorar las propiedades indefinidas.
Ric Jafe

55
Esta es una configuración predeterminada muy estúpida en mi humilde opinión, si agrega una propiedad a su API, toda la serialización falla
headsvk

481

Puedes usar

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

Ignorará todas las propiedades que no están declaradas.


55
Esto no funcionó para mí, todavía falla en propiedades desconocidas
Denis Kniazhev

1
¿Podría pegar al menos un fragmento de código exactamente lo que está haciendo? Es posible que haya perdido algo allí ... Al hacer esto o al usar "@JsonIgnoreProperties (ignoreUnknown = true)" Su problema debería resolverse. De todos modos buena suerte.
Suresh

27
FWIW - Tuve que importar esta enumeración ligeramente diferente: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
raf

99
^ Arriba es para las versiones de Jackson anteriores a 2
755

10
También puede encadenar estas llamadas como: getObjectMapper (). Disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
icfantv

126

La primera respuesta es casi correcta, pero lo que se necesita es cambiar el método getter, NO el campo: el campo es privado (y no se detecta automáticamente); Además, los captadores tienen prioridad sobre los campos si ambos son visibles (también hay formas de hacer visibles los campos privados, pero si desea tener captador no tiene mucho sentido)

Por lo tanto, getter debe nombrarse getWrapper()o anotarse con:

@JsonProperty("wrapper")

Si prefiere el nombre del método getter tal como está.


Por favor, explique: ¿qué captador necesita ser cambiado o anotado?
Frans

te refieres a anotado con @JsonGetter ("envoltorio"), ¿verdad?
pedram bashiri

@pedrambashiri No, quiero decir @JsonProperty. Si bien @JsonGetteres un alias legal, rara vez se utiliza como @JsonPropertyobras para captadores, establecedores y campos; los definidores y captadores se pueden distinguir por firma (uno no toma argumentos, devuelve no nulo; otro toma un argumento).
StaxMan

¡Esta es la respuesta que estaba buscando! Parece que Jackson tiene problemas para asignar el JSON de origen a su POJO, pero puede garantizar coincidencias etiquetando a los captadores. ¡Gracias!
Andrew Kirna

90

usando Jackson 2.6.0, esto funcionó para mí:

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

y con ajuste:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Con esa configuración la anotación es innecesaria
neworld

¿Necesita configurar ObjectMapper y Annotation en la clase? Supongo que objectMapper se solucionará para todos, sin necesidad de anotar cada clase. Aunque uso la anotación.
prayagupd

No necesita ambas configuraciones en la misma clase. También puede usar DI para obtener una instancia global de singleton de ObjectMapper, para establecer la FAIL_ON_UNKNOWN_PROPERTIESpropiedad globalmente.
user991710

No necesita ambos, puede elegir uno u otro.
heez

58

Se puede lograr de 2 maneras:

  1. Marque el POJO para ignorar propiedades desconocidas

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Configure ObjectMapper que serializa / des-serializa el POJO / json de la siguiente manera:

    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
¿Por qué debería ser esta la respuesta aceptada? Esto solo indica que ignore las propiedades desconocidas, mientras que la pregunta era encontrar una manera de envolver el json en un objeto que esta solución dice claramente que ignore.
Sayantan

42

Esto funcionó perfectamente para mí

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

@JsonIgnoreProperties(ignoreUnknown = true) anotación no lo hizo.


2
Votado como no responde a la pregunta del OP. Ignorar las propiedades desconocidas no resuelve su problema, pero lo deja con una Wrapperinstancia donde la lista de estudiantes está nullvacía.
Frans

37

Esto funciona mejor que Todos, consulte esta propiedad.

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

Trabajando como se esperaba!
MADHAIYAN M

Sí, este es el que resolvió mi problema, que coincidía con el título de esta publicación.
Scott Langeberg

Las respuestas me funcionan bien y es muy fácil. Gracias
Touya Akira

29

Si está usando Jackson 2.0

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

¿Por qué esta configuración no tiene ningún efecto para mí?
zhaozhi

@zhaozhi Depende de la versión de Jackson
Aalkhodiry

20

Según el documento , puede ignorar los campos seleccionados o todos los campos desconocidos:

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

Me funcionó con el siguiente código:

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

15

Al agregar setters y getters se resolvió el problema , lo que sentí es que el problema real era cómo resolverlo, pero no cómo suprimir / ignorar el error. Recibí el error " Campo no reconocido ... no marcado como ignorable ... "

Aunque utilizo la anotación a continuación en la parte superior de la clase, no pude analizar el objeto json y darme la entrada

@JsonIgnoreProperties (ignoreUnknown = true)

Entonces me di cuenta de que no agregué setters y getters, después de agregar setters y getters al "Wrapper" y al "Estudiante" funcionó a las mil maravillas.


Esta parece ser la única respuesta que realmente responde la pregunta. Todas las otras respuestas solo marcan propiedades desconocidas como ignoradas, pero 'wrapper' no es una propiedad desconocida, es lo que estamos tratando de analizar.
lbenedetto

14

Jackson se queja porque no puede encontrar un campo en su clase Wrapper que se llama "wrapper". Hace esto porque su objeto JSON tiene una propiedad llamada "contenedor".

Creo que la solución es cambiar el nombre del campo de la clase Wrapper a "wrapper" en lugar de "students".


Gracias Jim Lo intenté y no solucionó el problema. Me pregunto si me falta alguna anotación ..
jshree

1
Hmm, qué sucede cuando creas los datos equivalentes en Java y luego usas Jackson para escribirlos en JSON. Cualquier diferencia entre ese JSON y el JSON anterior debería ser una pista de lo que va mal.
Jim Ferrans

Esta respuesta funcionó para mí, con el ejemplo de la pregunta.
sleske

14

He probado el siguiente método y funciona para tal lectura de formato JSON con Jackson. Utilice la solución ya sugerida de: anotar getter con@JsonProperty("wrapper")

Tu clase de envoltura

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

Mi sugerencia de clase de envoltura

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

Sin embargo, esto le daría la salida del formato:

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

También para obtener más información, consulte https://github.com/FasterXML/jackson-annotations

Espero que esto ayude


Bienvenido a stackoverflow. Consejo, puede usar los {}símbolos en la barra de herramientas para formatear los fragmentos de código.
Leigh

11

Esta solución es genérica al leer transmisiones json y necesita obtener solo algunos campos, mientras que los campos no asignados correctamente en sus clases de dominio se pueden ignorar:

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

Una solución detallada sería usar una herramienta como jsonschema2pojo para autogenerar las clases de dominio requeridas, como Student, del esquema de la respuesta json. Puede hacer esto último con cualquier convertidor de json a esquema en línea.


10

Anote los estudiantes de campo como se muestra a continuación, ya que no hay coincidencia en los nombres de las propiedades json y java

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

9

Como nadie más ha mencionado, pensé que lo haría ...

El problema es que su propiedad en su JSON se llama "envoltorio" y su propiedad en Wrapper.class se llama "estudiantes".

Entonces tampoco ...

  1. Corrija el nombre de la propiedad en la clase o en JSON.
  2. Anote su variable de propiedad según el comentario de StaxMan.
  3. Anote el setter (si tiene uno)

6

establecer público sus campos de clase no privados .

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

2
mala práctica: esto rompe la encapsulación.
Downhillski

1
He oído que.
Downhillski, el

Su clase está en riesgo cuando el usuario la usa porque el estado interno podría mutar a través de estos campos.
Downhillski, el

5

Lo que funcionó para mí fue hacer pública la propiedad. Resolvió el problema para mí.


1
Trabajó para mí: D
TienLuong

5

Cualquiera de los cambios

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

a

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

---- o ----

Cambie su cadena JSON a

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

5

Tu aportación

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

indica que es un objeto, con un campo llamado "contenedor", que es una colección de estudiantes. Entonces mi recomendación sería

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

donde Wrapperse define como

class Wrapper {
    List<Student> wrapper;
}

5

El nuevo Android Firebase introdujo algunos cambios enormes; debajo de la copia del documento:

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

Actualiza tus objetos de modelo Java

Al igual que con el SDK 2.x, Firebase Database convertirá automáticamente los objetos Java que pasas a DatabaseReference.setValue()JSON y puede leer JSON en objetos Java usando DataSnapshot.getValue().

En el nuevo SDK, al leer JSON en un objeto Java con DataSnapshot.getValue(), las propiedades desconocidas en el JSON ahora se ignoran de manera predeterminada, por lo que ya no necesita@JsonIgnoreExtraProperties(ignoreUnknown=true) .

Para excluir campos / captadores al escribir un objeto Java en JSON, ahora se llama a la anotación en @Excludelugar 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)

Si hay una propiedad adicional en su JSON que no está en su clase Java, verá esta advertencia en los archivos de registro:

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

Puedes deshacerte de esta advertencia poniendo una @IgnoreExtraPropertiesanotación en tu clase. Si desea que Firebase Database se comporte como lo hizo en el 2.x SDK y arroje una excepción si hay propiedades desconocidas, puede poner una @ThrowOnExtraPropertiesanotación en su clase.


4

Por mi parte, la única línea

@JsonIgnoreProperties(ignoreUnknown = true)

tampoco funcionó

Solo agrega

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Esto funcionó perfectamente para mí

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Solucioné este problema simplemente cambiando las firmas de mi setter y métodos getter de mi clase POJO. Todo lo que tenía que hacer era cambiar el método getObject para que coincidiera con lo que estaba buscando el asignador. En mi caso, tenía un getImageUrl originalmente, pero los datos de JSON tenían image_url que estaba arrojando el mapeador. Cambié mi setter y getters a getImage_url y setImage_url .

Espero que esto ayude.


aparentemente tiene razón: si el nombre que desea es xxx_yyy La forma de llamarlo sería getXxx_yyy y setXxx_yyy. Esto es muy extraño pero funciona.
sivi

3

El POJO debe definirse como

Clase de respuesta

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

Clase de envoltura

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

y mapeador para leer el valor

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

Casi. No wrappers, pero wrapper.
Frans

@Frans Jaja, gracias por detectar el error. Naturalmente uso plural para una colección. Pero según la pregunta de OP, debería ser singular.
Dino Tw

3

Esta puede ser una respuesta muy tardía, pero solo cambiar el POJO a esto debería resolver la cadena json provista en el problema (ya que la cadena de entrada no está bajo su control como usted dijo):

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

3

Otra posibilidad es esta propiedad en application.properties spring.jackson.deserialization.fail-on-unknown-properties=false, que no necesitará ningún otro cambio de código en su aplicación. Y cuando crea que el contrato es estable, puede eliminar esta propiedad o marcarla como verdadera.


3

Puede que este no sea el mismo problema que tuvo el OP, pero en caso de que alguien llegue aquí con el mismo error que yo tuve, esto los ayudará a resolver su problema. Obtuve el mismo error que el OP cuando utilicé un ObjectMapper de una dependencia diferente a la anotación JsonProperty.

Esto funciona:

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

No funciona:

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

¡Gracias! import com.fasterxml.jackson.annotation.JsonProperty funcionó para mí en lugar del otro :-)
phil

2

Google me trajo aquí y me sorprendió ver las respuestas ... ¡todas sugirieron evitar el error ( que siempre se repite 4 veces más tarde en el desarrollo ) en lugar de resolverlo hasta que este caballero restaurado por fe en SO!

objectMapper.readValue(responseBody, TargetClass.class)

se usa para convertir una cadena json en un objeto de clase, lo que falta es que TargetClassdebe tener gettérminos públicos set. ¡Lo mismo falta en el fragmento de pregunta de OP también! :)

a través de lombok, tu clase como se muestra a continuación debería funcionar.

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

2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Tal vez algunas explicaciones o documentos adicionales serían buenos
Benj

@JsonIgnoreProperties (ignoreUnknown = true) funciona bien, gracias
Guilherme
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.