[译]通过 GsonHttpMessageConverter 在 Spring 中配置 Gson

原文地址:Configure gson in spring using GsonHttpMessageConverter

Jackson一直是springframework默认的json库,直到4.1版本它添加了对GsonHttpMessageConverter的支持。为了使用谷歌Gson库中的Gson类,让我们来看看如何配置你的spring应用。

开始

在我们开始之前有必要了解一下Spring是如何将Objects转换为Json的。在典型的Spring MVC中,一旦请求退出后,那么@Controller注解就会去渲染一个视图。我们可以通过@RequestBody或者@RestController这种注解来请求Spring,并且可以直接将Model中的java对象如何到Response中。在我们演示的Json中,当这样做时,Spring将会专门寻找一个与mime类型相似的HttpMessageConvert来执行转换操作。Spring已经设置了默认的MappingJackon2HttpMessageConvert,所以我们希望将其替换为GsonHttpMessageConvert,这样Spring就可以使用Gson来转换Java对象。

在Spring boot中配置Gson

添加Gson到Classpath

如果你正准备将Gson提供给Spring boot来执行转换操作,你应该首先来看看HttpMessageConvertersAutoConfig,因为它随时都有可能被改变。在写这篇教程时HttpMessageConvertersAutoConfig已经存在,如果Gson在你的Classpath路径下,GsonHttpMessageConverter就会被创建,这个应用不包含Jackson的JsonGenerator类,并且Gson bean也不存在。

@Configuration
@ConditionalOnClass(Gson.class)
@ConditionalOnMissingClass(name = "com.fasterxml.jackson.core.JsonGenerator")
@ConditionalOnBean(Gson.class)
protected static class GsonHttpMessageConverterConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
        GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
        converter.setGson(gson);
        return converter;
    }

}
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.3.1</version>
</dependency>

从Classpath中排除Jackson

如果你想确保Jackson没有被使用或者你遇到了冲突,你可以添加@EnableAutoConfiguration(exclude = { JacksonAutoConfiguration.class })到你的Class中,并且从spring-boot-starter-web的依赖中排除它。

@SpringBootApplication
@EnableAutoConfiguration(exclude = { JacksonAutoConfiguration.class })
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
        <exclusion>
            <artifactId>jackson-databind</artifactId>
            <groupId>com.fasterxml.jackson.core</groupId>
        </exclusion>
    </exclusions>
</dependency>

如果你试图消除对Jackson的依赖,我们通过本教程注意到,如果你正在EndpointAutoConfiguration类中使用spring boot actuator,那么Jackson是必需的并且这样做会报告github issue。

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configurationPropertiesReportEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.ConfigurationPropertiesReportEndpoint]: Factory method 'configurationPropertiesReportEndpoint' threw exception; nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/ser/BeanSerializerModifier

验证请求

让我们来创建一个Controller,它可以返回一个hashmap来验证GsonHttpMessageConvert生效了。我们将要修改我们的application.properties配置文件,它里面包含了logging.level.org.springframework=DEBUG这个配置项,然后对默认的request mapping发送一个请求。检查日志我们可以看到GsonHttpMessageConverter被使用了。

@RestController
public class MyController {

    @RequestMapping(value = "/",
            produces = { MediaType.APPLICATION_JSON_VALUE },
            method = RequestMethod.GET)
    public ResponseEntity<Map<String, String>> getContacts() {

        Map<String, String> dummyData = new HashMap<>();

        dummyData.put("java-examples",
                "http://www.leveluplunch.com/java/examples/");
        dummyData.put("groovy-examples",
                "http://www.leveluplunch.com/groovy/examples/");

        return new ResponseEntity<Map<String, String>>(dummyData, HttpStatus.OK);
    }
}
2015-01-18 07:33:51.673 DEBUG 18971 --- [nio-8080-exec-6] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Written [{java-examples=http://www.leveluplunch.com/java/examples/, groovy-examples=http://www.leveluplunch.com/groovy/examples/}] as "application/json" using [org.springframework.http.converter.json.GsonHttpMessageConverter@469047b8]

使用HttpMessageConverters来定制转换器

如果你正在讨论或者对通过复写bean来定制化一个已经存在的转换器时遇到问题,spring-boot提供了一个替换方案。这个方法允许你在classpath中同时存在gson和jackson。我们会创建一个CustomConfiguration类,但它可以在人和包含@Configuration注解的类中运行,然后创建一个新的HttpMessageConverters。在我们的配置中我们将会指定springframework来使用默认的HttpMessageConvert,然后返回GsonHttpMessageConverter

@Configuration
public class CustomConfiguration {

    @Bean
    public HttpMessageConverters customConverters() {

        Collection<HttpMessageConverter<?>> messageConverters = new ArrayList<>();

        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        messageConverters.add(gsonHttpMessageConverter);

        return new HttpMessageConverters(true, messageConverters);
    }
}

如果我们包含了gson的pom依赖,并且指定了customConverters,那么springframework会配置并使用GsonHttpMessageConverter。现在你可能会问,如果jsckson也存在classpath下,这种情况是如何工作的?当添加了一个新的转换器之后,HttpMessageConverters默认的行为是将它添加在列表的前面,因此在jackson工作前它就已经被配置了。

使用java配置

如果你没有使用spring boot,你可能仍然在你的应用中使用继承自WebMvcConfigureAdapter的javaconfig来配置gson,或者你使用WebMvcConfigurationSupport但需要跟过的控制权。你可以阅读更多有关如何定制已提供的spring mvc配置。

@Configuration
@EnableWebMvc
public class Application extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter < ? >> converters) {
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        converters.add(gsonHttpMessageConverter);
    }
}

使用XML配置文件来配置Gson

我没有为了配置gson而添加一个特定的测试场景,用于配置基于xml应用程序的gson,但它看起来和下面的内容很相似:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.GsonHttpMessageConverter"/>
        </list>
    </property>
</bean>

对于哪个java库是最快的json解析程序有很多的争论,一旦java 8的json api得到加强时,这些争论可能就此消失。所以到那个时候就可以选择一个方法和一个库。

发表评论

电子邮件地址不会被公开。 必填项已用*标注