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)
jshree
fuente
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)
Ariel Kogan
fuente
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.

Suresh
fuente
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á.

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

Felix Kimutua
fuente
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);
usuario2542697
fuente
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);
Aalkhodiry
fuente
¿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)
tomrozb
fuente
15

Me funcionó con el siguiente código:

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

ddc
fuente
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".

Jim Ferrans
fuente
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

mytwocentsads
fuente
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.

George Papatheodorou
fuente
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
}
ajith r
fuente
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)
TedTrippin
fuente
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
}
nunca invierno
fuente
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í.

Rohitesh
fuente
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"}]}
sagar
fuente
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;
}
Ran0990BK
fuente
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.

ThierryC
fuente
4

Por mi parte, la única línea

@JsonIgnoreProperties(ignoreUnknown = true)

tampoco funcionó

Solo agrega

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0

jodu
fuente
4

Esto funcionó perfectamente para mí

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

superusuario
fuente
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);
Dino Tw
fuente
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
}
Sayantan
fuente
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.

krmanish007
fuente
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
cwa
fuente
¡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;
}
NoobEditor
fuente
2

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties

Gank
fuente
Tal vez algunas explicaciones o documentos adicionales serían buenos
Benj
@JsonIgnoreProperties (ignoreUnknown = true) funciona bien, gracias
Guilherme