Spring Boot 不使用配置的 Jackson ObjectMapper 和 @EnableWebMvc

Tom*_*Tom 2 spring-mvc jackson spring-boot

我想ObjectMapper在我的项目中使用 Jackson 的配置版本(忽略空值和 snake_case,也使用一些自定义模块)。

在我的大型项目中,我无法让 Spring MVC 实际使用这个映射器。

build.gradle:

buildscript {
  ext {
    springBootVersion = '1.5.6.RELEASE'
  }
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
  }
}

apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
  mavenCentral()
}

dependencies {
  compile('org.springframework.boot:spring-boot-starter')
  compile("org.springframework.boot:spring-boot-starter-jetty:${springBootVersion}")
  compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")

  compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.8.8'
  compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.8'

  testCompile('org.springframework.boot:spring-boot-starter-test')
}
Run Code Online (Sandbox Code Playgroud)

我的应用程序.yml:

spring:
  application:
  name: Jackson test
jackson:
  property-naming-strategy: SNAKE_CASE
  default-property-inclusion: non_empty
debug: true
Run Code Online (Sandbox Code Playgroud)

一个容器类:

public class MyLocationEntity {
    public String nameAndSnake;
}
Run Code Online (Sandbox Code Playgroud)

一个配置类:

@Configuration
@EnableWebMvc
public class AppConfig {
}
Run Code Online (Sandbox Code Playgroud)

还有一个控制器:

@RestController
@RequestMapping("/test")
public class TestController {

  @Autowired
  private ObjectMapper objectMapper;

  @RequestMapping(value = "/test", produces = "application/json")
  public MyLocationEntity test() throws JsonProcessingException {
    MyLocationEntity location = new MyLocationEntity();
    location.nameAndSnake = "hello world";
    String expexted = objectMapper.writeValueAsString(location);
    return location;
  }
}
Run Code Online (Sandbox Code Playgroud)

如果我现在查看expected调试器中的值,它是{"name_and_snake":"hello world"}. 但是如果我让控制器运行,实际响应是{"nameAndSnake":"hello world"}.

当我删除@EnableWebMvc它时。如何将配置的映射器与 MVC 一起使用,而不删除 Web MVC 的其余自动配置?

M. *_*tin 5

仅从 Javadocs 中并不明显,但@EnableWebMvc禁用了由 提供的 Spring Boot 默认 Web MVC 自动配置WebMvcAutoConfiguration,包括使用ObjectMapperapplication.yml属性配置的 Jackson bean 。根据Spring Boot 参考文档

9.4.7. 关闭默认 MVC 配置

完全控制 MVC 配置的最简单方法是提供您自己@Configuration@EnableWebMvc注释。这样做会将所有 MVC 配置都掌握在您手中。

因此,必须手动配置 MVC 配置,以便application.yml@EnableWebMvc注解一起使用 Spring Boot属性。对此有几种不同的可能方法。

第一种方法是从WebMvcAutoConfiguration.EnableWebMvcConfiguration.configureMessageConverters(). 这将替换消息转换器 - 包括MappingJackson2HttpMessageConverter包含未配置的ObjectMapper- 与默认 Spring Boot 配置一起使用的:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private ObjectProvider<HttpMessageConverters> messageConvertersProvider;

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        this.messageConvertersProvider
                .ifAvailable((customConverters) -> converters.addAll(customConverters.getConverters()));
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,不是使用默认的 Spring Boot 消息转换器列表,而是可以只交换Spring Boot 提供的ObjectMapperor MappingJackson2HttpMessageConverterbean(application.yml应用了属性):

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.stream()
                .filter(c -> c instanceof MappingJackson2HttpMessageConverter)
                .map(c -> (MappingJackson2HttpMessageConverter) c)
                .forEach(c -> c.setObjectMapper(objectMapper));

    }
}
Run Code Online (Sandbox Code Playgroud)

或者

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (int i = 0; i < converters.size(); i++) {
            if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) {
                converters.set(i, mappingJackson2HttpMessageConverter);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)