Spring MVC отображение карт для Google-GSON? - PullRequest
13 голосов
/ 20 сентября 2010

Кто-нибудь знает, существует ли представление отображения Spring MVC для Gson ? Я ищу что-то похожее на org.springframework.web.servlet.view.json.MappingJacksonJsonView .

В идеале он взял бы мой ModelMap и отобразил бы его как JSON, соблюдая мои renderedAttributes, установленные в объявлении ContentNegotiatingViewResolver

Мы планируем широко использовать Gson в приложении, так как он кажется безопаснее и лучше, чем Джексон. Тем не менее, мы застряли в связи с необходимостью иметь две разные библиотеки JSON для создания собственных представлений JSON.

Заранее спасибо!

[кросс-пост Весенние форумы ]

Ответы [ 2 ]

11 голосов
/ 13 декабря 2012

aweigold помог мне пройти большую часть пути, но конкретно описать решение для конфигурации Spring 3.1 Java на основе вот что я сделал.* spring-android-rest-template project.

Зарегистрируйте 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.

5 голосов
/ 04 января 2012

Я бы порекомендовал расширить AbstractView так же, как это делает MappingJacksonJsonView.

Лично для 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...