json - servicios - RESTO con enlaces de datos completos de Spring y Jackson
spring rest json (5)
Descubrí que también puede solucionar el problema del borrado de tipo utilizando una matriz como @RequestBody en lugar de una colección. Por ejemplo, lo siguiente funcionaría:
public @ResponseBody String executeActions(@RequestBody ActionImpl[] actions) { //... }
Estoy usando Spring MVC para manejar las solicitudes JSON POST. Debajo de las portadas, estoy usando el MappingJacksonHttpMessageConverter creado en el procesador Jackson JSON y habilitado cuando usa el mvc: anotado por la anotación.
Uno de mis servicios recibe una lista de acciones:
@RequestMapping(value="/executeActions", method=RequestMethod.POST)
public @ResponseBody String executeActions(@RequestBody List<ActionImpl> actions) {
logger.info("executeActions");
return "ACK";
}
Descubrí que Jackson asigna el cuerpo de solicitud a una Lista de elementos java.util.LinkedHashMap (enlace de datos simple). En cambio, me gustaría que la solicitud se vincule a una Lista de objetos tipeados (en este caso, "ActionImpl").
Sé que esto es fácil de hacer si usas el ObjectMapper de Jackson directamente:
List<ActionImpl> result = mapper.readValue(src, new TypeReference<List<ActionImpl>>() { });
pero me preguntaba cuál es la mejor manera de lograr esto al usar Spring MVC y MappingJacksonHttpMessageConverter. ¿Algún consejo?
Gracias
Esta pregunta ya es antigua, pero creo que puedo contribuir un poco de todos modos.
Al igual que StaxMan señaló, esto se debe al borrado de tipo. Definitivamente debería ser posible, porque puede obtener los argumentos genéricos a través de la reflexión de la definición del método. Sin embargo, el problema es la API de HttpMessageConverter :
T read(Class<? extends T> clazz, HttpInputMessage inputMessage);
Aquí, solo List.class se pasará al método. Entonces, como puede ver, es imposible implementar un HttpMessageConverter que calcule el tipo real mirando el tipo de parámetro de método, ya que no está disponible.
Sin embargo, es posible codificar su propia solución: simplemente no usará HttpMessageConverter. Spring MVC le permite escribir su propio WebArgumentResolver que se inicia antes de los métodos de resolución estándar. Por ejemplo, puede usar su propia anotación personalizada (@JsonRequestBody?) Que usa directamente un ObjectMapper para analizar su valor. Podrá proporcionar el tipo de parámetro desde el método:
final Type parameterType= method.getParameterTypes()[index];
List<ActionImpl> result = mapper.readValue(src, new TypeReference<Object>>() {
@Override
public Type getType() {
return parameterType;
}
});
En realidad no es la forma en que se pretendía utilizar TypeReference, supongo, pero ObjectMapper no proporciona un método más adecuado.
Has intentado declarar el método como:
executeActions(@RequestBody TypeReference<List<ActionImpl>> actions)
No lo he intentado, pero en base a su pregunta, es lo primero que probaría.
Para su información, la función estará disponible en Spring 3.2 (consulte https://jira.springsource.org/browse/SPR-9570 )
Acabo de probarlo en el M2 actual y funciona como un encanto listo para usar (no es necesario proporcionar una anotación adicional para proporcionar el tipo parametrizado, será resuelto automáticamente por el nuevo MessageConverter)
Sospecho que el problema se debe al borrado de tipo, es decir, en lugar de pasar el tipo de parámetro genérico, tal vez solo se pase actions.getClass (); y esto daría un tipo equivalente a List <?>.
Si esto es cierto, una posibilidad sería usar una subclase intermedia, como:
public class ActionImplList extends ArrayList<ActionImpl> { }
porque esto retendrá la información de tipo incluso si solo se pasa la clase. Por lo que entonces:
public @ResponseBody String executeActions(@RequestBody ActionImplList actions)
Haría el truco. No es óptimo, pero debería funcionar.
Espero que alguien con más conocimientos de Spring MVC pueda arrojar luz sobre por qué no se pasa el tipo de parámetro (¿quizás es un error?), Pero al menos hay una solución alternativa.