Domanda

sto usando Spring MVC per gestire le richieste JSON POST. Sotto le coperte sto usando il MappingJacksonHttpMessageConverter costruita sul processore Jackson JSON e attivato 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<ActionImpl> actions) {
        logger.info("executeActions");
        return "ACK";
    }

Ho scoperto che Jackson mappa la requestBody a un elenco di articoli java.util.LinkedHashMap (associazione dati semplici). Invece, vorrei che la richiesta di essere associato a un elenco di oggetti tipizzati (in questo caso "ActionImpl").

So che questo è facile da fare se si utilizza direttamente di Jackson ObjectMapper:

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

ma mi chiedevo qual è il modo migliore per raggiungere questo quando si utilizza Spring MVC e MappingJacksonHttpMessageConverter. Eventuali suggerimenti?

Grazie

È stato utile?

Soluzione

I problema sospetto è dovuto alla cancellazione del tipo, vale a dire invece di passare generico tipo di parametro, forse solo actions.getClass () viene passato; e questo darebbe tipo equivalente di List .

Se questo è vero, una possibilità sarebbe quella di utilizzare un sub-classe intermedia, come:

public class ActionImplList extends ArrayList<ActionImpl> { }

, perché questo sarà il tipo di conservare le informazioni anche se è passato unica classe. Allora:

public @ResponseBody String executeActions(@RequestBody ActionImplList actions)

farebbe il trucco. Non ottimale, ma dovrebbe funzionare.

Spero che qualcuno con più Spring MVC conoscenza può far luce sul motivo per cui non viene passato tipo di parametro (forse si tratta di un bug?), Ma almeno c'è un lavoro in giro.

Altri suggerimenti

ho scoperto che è anche possibile aggirare il problema cancellazione tipo utilizzando un array come @RequestBody invece di una collezione. Ad esempio, il seguente dovrebbe funzionare:

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

Per vostra informazione, la funzione sarà disponibile nella primavera del 3.2 (vedi https://jira.springsource.org/browse / SPR-9570 )

Ho appena testato su corrente M2 e funziona come un fascino fuori dalla scatola (non c'è bisogno di fornire l'annotazione additionnal di fornire il tipo parametrico, sarà risolto automaticamente dal nuovo MessageConverter)

Questa domanda è già vecchio, ma penso di poter contribuire un po 'in ogni caso.

Come StaxMan sottolineato, questo è dovuto alla cancellazione del tipo. E 'sicuramente dovrebbe essere possibile, perché possono ottenere gli argomenti generici attraverso la riflessione dalla definizione del metodo. Tuttavia, il problema è l'API della HttpMessageConverter :

T read(Class<? extends T> clazz, HttpInputMessage inputMessage);

Qui, solo List.class verrà passato al metodo. Quindi, come potete vedere, non è possibile implementare un HttpMessageConverter che calcola il tipo reale guardando il tipo di parametro del metodo, come che non è disponibile.

Tuttavia, è possibile codificare la propria soluzione - non si prevede di utilizzare HttpMessageConverter. Spring MVC consente di scrivere il proprio WebArgumentResolver che calci prima che i metodi di risoluzione standard. È possibile ad esempio utilizzare il proprio annotazioni personalizzate (@JsonRequestBody?) Che utilizza direttamente un ObjectMapper per analizzare il vostro valore. Sarete in grado di fornire il tipo di parametro dal metodo:

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

Non è davvero il modo TypeReference era destinato ad essere utilizzato presumo, ma ObjectMapper non fornisce un metodo più adatto.

Hai provato dichiarando il metodo come:

executeActions(@RequestBody TypeReference<List<ActionImpl>> actions)

Non ho provato, ma in base alla tua domanda è la prima cosa che ho farebbe prova.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top