deserialize - No se puede deserializar la instancia de java.util.ArrayList fuera de VALUE_STRING
json to arraylist java (4)
Esta es la solución para mi vieja pregunta:
Implementé mi propio ContextResolver para habilitar la función DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY.
package org.lig.hadas.services.mapper;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
@Produces(MediaType.APPLICATION_JSON)
@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper>
{
ObjectMapper mapper;
public ObjectMapperProvider(){
mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
Y en el web.xml registré mi paquete en la definición del servlet ...
<servlet>
<servlet-name>...</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>...;org.lig.hadas.services.mapper</param-value>
</init-param>
...
</servlet>
... todo el resto está hecho de manera transparente por jersey / jackson.
Tengo un servicio REST construido con Jersey y desplegado en App Engine. El servicio REST implementa el verbo PUT que consume un tipo de aplicación / json. El enlace de datos es realizado por Jackson.
El verbo consume una relación de departamentos de empresa representada en JSON como
{"name":"myEnterprise", "departments":["HR","IT","SC"]}
En el lado del cliente, uso gson para convertir la representación JSON en un objeto java. Luego, paso el objeto a mi servicio REST y funciona bien.
Problema:
Cuando mi representación JSON tiene solo un elemento en la colección
{"name":"myEnterprise", "departments":["HR"]}
el servicio no puede deserializar el objeto.
ATTENTION: /enterprise/enterprise: org.codehaus.jackson.map.JsonMappingException:
Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token at
[Source: org.mortbay.jetty.HttpParser$Input@5a9c5842; line: 1, column: 2
Según informaron otros usuarios, la solución es agregar el indicador ACCEPT_SINGLE_VALUE_AS_ARRAY (por ejemplo, Jersey: no se puede deserializar la instancia de ArrayList fuera de String ). Sin embargo, no estoy controlando un ObjectMapper porque, en el lado del servicio, Jackson lo hace de forma transparente.
Pregunta:
¿Hay alguna forma de configurar ObjectMapper en el lado del servicio para habilitar ACCEPT_SINGLE_VALUE_AS_ARRAY? anotaciones? web.xml?
Detalles del código
Objeto Java:
@XmlRootElement
public class Enterprise {
private String name;
private List<String> departments;
public Enterprise() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getDepartments() {
return departments;
}
public void setDepartments(List<String> departments) {
this.departments = departments;
}
}
El lado del servicio REST:
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("/enterprise")
public Response putEnterprise(Enterprise enterprise,
@Context HttpServletRequest req){
...
}
Lado del cliente:
...
String jsonString = "{/"name/":/"myEnterprise/", /"departments/":[/"HR/"]}";
Enterprise enterprise = gson.fromJson(jsonString, Enterprise.class);
System.out.println(gson.toJson(enterprise));
response = webResource
.type(MediaType.APPLICATION_JSON)
.put(ClientResponse.class,enterprise);
if (response.getStatus() >= 400) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
...
Establecer este atributo en la instancia de ObjectMapper funciona,
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
Para las personas que encuentran esta pregunta buscando el mensaje de error, también puede ver este error si cometen un error en sus anotaciones @JsonProperty
, de manera que anoten una propiedad de tipo List
con el nombre de un campo de un solo valor:
@JsonProperty("someSingleValuedField") // Oops, should have been "someMultiValuedField"
public List<String> getMyField() { // deserialization fails - single value into List
return myField;
}
lo intentas
[{"name":"myEnterprise", "departments":["HR"]}]
la llave cuadrada es el punto clave.