REST con Spring e Jackson dati completi vincolanti

Sto usando Spring MVC per gestire le richieste POST JSON. Sotto le copertine sto usando il MappingJacksonHttpMessageConverter costruito sul processore Jackson JSON e abilitato quando si utilizza il mvc: annotation-driven.

Uno dei miei servizi riceve un elenco di azioni:

@RequestMapping(value="/executeActions", method=RequestMethod.POST) public @ResponseBody String executeActions(@RequestBody List actions) { logger.info("executeActions"); return "ACK"; } 

Ho trovato che Jackson mappa la richiestaBody in un elenco di elementi java.util.LinkedHashMap (semplice associazione dati). Invece, vorrei che la richiesta venisse associata a un elenco di oggetti digitati (in questo caso “ActionImpl”).

So che è facile farlo se usi direttamente l’ObjectMapper di Jackson:

 List result = mapper.readValue(src, new TypeReference<List>() { }); 

ma mi stavo chiedendo quale sia il modo migliore per ottenere questo risultato usando Spring MVC e MappingJacksonHttpMessageConverter. Qualche suggerimento?

Grazie

Sospetto che il problema sia dovuto alla cancellazione dei caratteri, ovvero, invece di passare il tipo di parametro generico, forse viene passato solo actions.getClass (); e questo darebbe un equivalente di tipo di lista .

Se questo è vero, una possibilità sarebbe quella di utilizzare una sottoclass intermedia, come:

 public class ActionImplList extends ArrayList { } 

perché questo conserverà le informazioni sul tipo anche se viene passata solo la class. Allora:

 public @ResponseBody String executeActions(@RequestBody ActionImplList actions) 

farebbe il trucco Non ottimale ma dovrebbe funzionare.

Spero che qualcuno con più conoscenze di Spring MVC possa far luce sul motivo per cui il tipo di parametro non viene passato (forse è un bug?), Ma almeno c’è un problema.

Ho scoperto che puoi anche aggirare il problema della cancellazione dei caratteri usando un array come @RequestBody invece di una raccolta. Ad esempio, il seguente potrebbe funzionare:

 public @ResponseBody String executeActions(@RequestBody ActionImpl[] actions) { //... } 

Per vostra informazione, la funzionalità sarà disponibile nella spring 3.2 (vedere https://jira.springsource.org/browse/SPR-9570 )

L’ho appena testato sull’attuale M2 e funziona come un fascino immediato (non è necessario fornire un’annotazione aggiuntiva per fornire il tipo parametrizzato, sarà automaticamente risolto dal nuovo MessageConverter)

Questa domanda è già vecchia, ma penso di poter contribuire un po ‘comunque.

Come ha sottolineato StaxMan, ciò è dovuto al tipo di cancellazione. Dovrebbe essere sicuramente ansible, perché è ansible ottenere gli argomenti generici tramite la riflessione dalla definizione del metodo. Tuttavia, il problema è l’API di HttpMessageConverter :

 T read(Class clazz, HttpInputMessage inputMessage); 

Qui, solo il List.class verrà passato al metodo. Quindi, come puoi vedere, è imansible implementare un HttpMessageConverter che calcola il tipo reale osservando il tipo di parametro del metodo, poiché non è disponibile.

Tuttavia, è ansible codificare la propria soluzione alternativa: non si utilizzerà HttpMessageConverter. Spring MVC consente di scrivere il proprio WebArgumentResolver che esegue il comando prima dei metodi di risoluzione standard. Ad esempio, puoi utilizzare la tua annotazione personalizzata (@JsonRequestBody?) Che utilizza direttamente un ObjectMapper per analizzare il tuo valore. Sarai in grado di fornire il tipo di parametro dal metodo:

 final Type parameterType= method.getParameterTypes()[index]; List result = mapper.readValue(src, new TypeReference>() { @Override public Type getType() { return parameterType; } }); 

Non è proprio il modo in cui dovrebbe essere usato TypeReference che presumo, ma ObjectMapper non fornisce un metodo più adatto.

Hai provato a dichiarare il metodo come:

 executeActions(@RequestBody TypeReference> actions) 

Non l’ho provato, ma in base alla tua domanda è la prima cosa che proverei.