14

Does anyone know if there is a Spring MVC mapping view for Gson? I'm looking for something similar to org.springframework.web.servlet.view.json.MappingJacksonJsonView.

Ideally it would take my ModelMap and render it as JSON, respecting my renderedAttributes set in the ContentNegotiatingViewResolver declaration

We plan to use Gson extensively in the application as it seems safer and better than Jackson. That said, we're getting hung up by the need to have two different JSON libraries in order to do native JSON views.

Thanks in advance!

[cross-posted to Spring forums]

4

2 回答 2

11

aweigold 让我获得了大部分的成功,但是为了具体概述基于 Spring 3.1 Java 的配置的解决方案,这就是我所做的。

spring-android-rest-template项目中获取 GsonHttpMessageConverter.java

GsonHttpMessageConverter在您的 MVC 配置中注册您的消息转换器。

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

Spring 文档概述了这个过程,但不是很清楚。为了让它正常工作,我不得不扩展WebMvcConfigurerAdapter,然后覆盖configureMesageConverters。完成此操作后,您应该能够在控制器方法中执行以下操作:

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

瞧!JSON 输出。

于 2012-12-13T17:45:45.313 回答
5

我建议像 MappingJacksonJsonView 一样扩展 AbstractView 。

就个人而言,对于 JSON,我更喜欢使用 @Responsebody,并且只返回对象而不是模型和视图,这样更容易测试。如果您想为此使用 GSON,只需创建一个自定义 HttpMessageConverter,如下所示:

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();
        }
    }
}

然后将其添加到处理程序适配器中的转换器列表中,如下所示:

@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;
}
于 2012-01-04T14:30:43.483 回答