Tengo un servicio web REST basado en JSON implementado usando: Jetty, Jersey, Jersey-JSON usando Jackson.
Uno de mis métodos recibe una instancia de Persona, que tiene un campo de tipo Lista . es decir:
Public class Person { List names; }
Si lo llamo con una matriz de nombres, ¡todo funciona bien! p.ej:
{ "names" : [ "Jhon", "Doe" ] }
Pero si la persona tiene solo un nombre, mi cliente crea un solo elemento de valor, por ejemplo:
{ "names" : "Jhon" }
Cuando trato de llamar al servicio con un valor único, recibo una excepción:
Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
Pregunta:
¿Cómo debo crear / configurar mi servicio web para poder deserializar el campo de matriz cuando se me envían como un elemento único?
–
Ya leí
Deserialización de Jackson – con ArrayList contenida
y
¿Cómo puedo personalizar la serialización de una lista de objetos JAXB a JSON?
Y esto que refiere la última respuesta:
El cliente de Jersey no puede deserializar los servicios json – excepción (no puede deserializar la instancia)
Jaxb json faltan corchetes para una matriz de elementos
Pero ninguno de esos arregla el problema.
¡Gracias de antemano!
Después de un largo día, y otro … después de leer muchos wikis y preguntas frecuentes, finalmente funciona.
Lo que hice:
La historia:
Estaba usando Jersey 1.13 que usa (creo) jaxb por defecto.
Lo cambié para usar Jackson
com.sun.jersey.api.json.POJOMappingFeature true
como se describe en:
https://stackoverflow.com/a/13895768/660990
Esto hizo que mi camiseta usara a Jackson, pero el problema sigue siendo; Jackson no puede deserializar la matriz todavía.
Forcé el uso de los proveedores de Jackson :
com.sun.jersey.config.property.packages your.project.packages; org.codehaus.jackson.jaxrs
https://stackoverflow.com/a/3143214/660990
Fue un paso necesario, pero no fue suficiente. Es necesario activar el indicador ACCEPT_SINGLE_VALUE_AS_ARRAY .
ObjectMapper objectMapper; objectMapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
Necesitaba definir deserializador personalizado
public class MyResolver implements ContextResolver { @Override public ObjectMapper getContext(final Class> objectType) { ... return objectMapper; } }
para hacer eso:
Customizing-ObjectMapper
Después de hacer todo esto todavía no funcionó …
Después de un poco más de tiempo de búsqueda, encontré:
Jackson 2.0 con Jersey 1.12
Eso discute problemas de dependencias ..
Esto reveló mi problema, Jersey v1.13 viene con Jackson v1.9.2 Necesito Jackson v2.0
Eliminé la dependencia de jersey-json, porque incluía jackson 1.9.2:
com.sun.jersey jersey-json
Y dependencia declarada directamente para:
com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider
Referencia:
jackson-jaxrs-json-provider
Nota: este cambio elimina la capacidad de Jersey de usar Jaxb o tirar.
Fuera del tema , puede ser interesante para alguien:
Configure Jersey / Jackson para NO utilizar la anotación de campo @XmlElement para la denominación de campos JSON
Los ejemplos 5.10 y 5.11 de esta página explican su problema exacto. Puede configurar el generador de JSON para forzar matrices para listas de un solo elemento, como por JSONConfiguration.mapped().arrays("names").build()
: JSONConfiguration.mapped().arrays("names").build()
.
Me funcionó agregando @JsonSerialize a la clase
@JsonSerialize Public class Person { List names; }
Puede hacer esto con anotaciones a nivel de clase, campo o método utilizando la anotación JsonFormat
@JsonFormat(with = Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) protected List list; public List getList() { return list; } public void setList(List list) { this.list = list; }
{"results": {"place": {"lang": "en-US","woeid": "2168606"}}}
&
{"results": {"place": [{"lang": "en-US","woeid": "2168606"}, {"lang": "en-US","woeid": "2168606"}]}}
este tipo de cómo hacerlo … al usar yahoo place api