2010-09-20 12 views
13

Qualcuno sa se esiste una vista di mappatura MVC primaverile per Gson? Sto cercando qualcosa di simile a org.springframework.web.servlet.view.json.MappingJacksonJsonView.Visualizzazione mappatura MVC primaverile per Google-GSON?

ideale sarebbe prendere il mio ModelMap e renderlo come JSON, rispettando i miei renderedAttributes fissati nella dichiarazione ContentNegotiatingViewResolver

Pensiamo di utilizzare GSON ampiamente nell'applicazione come sembra più sicuro e meglio di Jackson. Detto questo, ci sentiamo bloccati dalla necessità di avere due diverse librerie JSON per fare visualizzazioni JSON native.

Grazie in anticipo!

[Cross-postato a Spring forums]

+2

La cura di elaborare "sembra più sicuro e migliore"? Come in, meglio in che modo? (o più sicuro, per quella materia) – StaxMan

+0

+1, esattamente quello che stavo cercando pure. – Jonik

+0

Per tutti coloro che sono venuti qui a partire da Spring boot 5.0, controlla la mia risposta [force spring per usare GSON, invece di Jackson] (https://stackoverflow.com/a/48459787/6860188) – lordUhuru

risposta

5

Suggerirei di estendere AbstractView proprio come la MappingJacksonJsonView fa.

Personalmente, per JSON, preferisco usare @Responsebody e restituire l'oggetto piuttosto che un modello e una vista, questo rende più facile il test. Se si desidera utilizzare GSON per questo, basta creare un costume HttpMessageConverter come questo:

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import com.google.gson.JsonParseException; 
import com.google.gson.reflect.TypeToken; 
import com.vitalimages.string.StringUtils; 
import org.springframework.http.HttpInputMessage; 
import org.springframework.http.HttpOutputMessage; 
import org.springframework.http.MediaType; 
import org.springframework.http.converter.AbstractHttpMessageConverter; 
import org.springframework.http.converter.HttpMessageNotReadableException; 
import org.springframework.http.converter.HttpMessageNotWritableException; 
import org.springframework.stereotype.Component; 

import java.io.BufferedWriter; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.lang.reflect.Type; 
import java.nio.charset.Charset; 
import java.sql.Timestamp; 

@Component 
public class GSONHttpMessageConverter extends AbstractHttpMessageConverter<Object> { 

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); 

    private GsonBuilder gsonBuilder = new GsonBuilder() 
      .excludeFieldsWithoutExposeAnnotation() 
      .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") 
      .registerTypeAdapter(Timestamp.class, new GSONTimestampConverter()); 

    public GSONHttpMessageConverter() { 
     super(new MediaType("application", "json", DEFAULT_CHARSET)); 
    } 

    @Override 
    protected boolean supports(Class<?> clazz) { 
     // should not be called, since we override canRead/Write instead 
     throw new UnsupportedOperationException(); 
    } 

    @Override 
    public boolean canRead(Class<?> clazz, MediaType mediaType) { 
     return MediaType.APPLICATION_JSON.isCompatibleWith(mediaType); 
    } 

    public boolean canWrite(Class<?> clazz, MediaType mediaType) { 
     return MediaType.APPLICATION_JSON.isCompatibleWith(mediaType); 
    } 

    public void registerTypeAdapter(Type type, Object serializer) { 
     gsonBuilder.registerTypeAdapter(type, serializer); 
    } 

    @Override 
    protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { 
     try { 
      Gson gson = gsonBuilder.create(); 
      return gson.fromJson(StringUtils.convertStreamToString(inputMessage.getBody()), clazz); 
     } catch (JsonParseException e) { 
      throw new HttpMessageNotReadableException("Could not read JSON: " + e.getMessage(), e); 
     } 
    } 

    @Override 
    protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { 
     Type genericType = TypeToken.get(o.getClass()).getType(); 

     BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputMessage.getBody(), DEFAULT_CHARSET)); 
     try { 
      // See http://code.google.com/p/google-gson/issues/detail?id=199 for details on SQLTimestamp conversion 
      Gson gson = gsonBuilder.create(); 
      writer.append(gson.toJson(o, genericType)); 
     } finally { 
      writer.flush(); 
      writer.close(); 
     } 
    } 
} 

E poi aggiungerlo alla tua lista convertitore l'adattatore gestore in questo modo:

@Bean 
public HandlerAdapter handlerAdapter() { 
    final AnnotationMethodHandlerAdapter handlerAdapter = new AnnotationMethodHandlerAdapter(); 
    handlerAdapter.setAlwaysUseFullPath(true); 
    List<HttpMessageConverter<?>> converterList = new ArrayList<HttpMessageConverter<?>>(); 
    converterList.addAll(Arrays.asList(handlerAdapter.getMessageConverters())); 
    converterList.add(jibxHttpMessageConverter); 
    converterList.add(gsonHttpMessageConverter); 
    handlerAdapter.setMessageConverters(converterList.toArray(new HttpMessageConverter<?>[converterList.size()])); 
    return handlerAdapter; 
} 
+0

Puoi fare la stessa cosa con il bean ma in 'applicationContext.xml'? – 4gus71n

11

aweigold mi ha fatto la maggior parte del modo lì, ma per delineare concretamente una soluzione per la configurazione basata su Spring 3.1, ecco cosa ho fatto.

Grab GsonHttpMessageConverter.java dal progetto spring-android-rest-template.

Registra il tuo GsonHttpMessageConverter con i convertitori di messaggi nella tua configurazione MVC.

@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 
    @Override 
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
    converters.add(new GsonHttpMessageConverter()); 
    } 
} 

I documenti di primavera delineano questo processo, ma non sono chiari. Per fare in modo che funzioni correttamente, ho dovuto estendere WebMvcConfigurerAdapter e quindi ignorare configureMesageConverters. Dopo aver fatto questo, dovresti essere in grado di fare quanto segue nel tuo metodo di controllo:

@Controller 
public class AppController { 
    @RequestMapping(value = "messages", produces = MediaType.APPLICATION_JSON_VALUE) 
    public List<Message> getMessages() { 
    // .. Get list of messages 
    return messages; 
    } 
} 

E voilà! Uscita JSON.

+0

Grazie, mi ha davvero aiutato! Con Spring 3.2.2 e Jackson non sono riuscito a liberarmi del problema in cui si dice: 406 non accaptable. Ho fatto questo e ha funzionato, ma ho anche dovuto aggiungere al file xml del servizio. – user1051218

Problemi correlati