如何自定义Spring Boot隐式使用的Jackson JSON映射器?

Jon*_*nik 89 java spring spring-mvc jackson spring-boot

我正在使用Spring Boot(1.2.1),其方式与构建RESTful Web服务教程的方式类似:

@RestController
public class EventController {

    @RequestMapping("/events/all")
    EventList events() {
        return proxyService.getAllEvents();
    }

}
Run Code Online (Sandbox Code Playgroud)

所以上面,Spring MVC暗中使用Jackson将我的EventList对象序列化为JSON.

但我想对JSON格式进行一些简单的自定义,例如:

setSerializationInclusion(JsonInclude.Include.NON_NULL)
Run Code Online (Sandbox Code Playgroud)

问题是,自定义隐式JSON映射器的最简单方法什么?

我在这篇博客文章中尝试了这种方法,创建了一个CustomObjectMapper等等,但是第3步"在Spring上下文中注册类"失败了:

org.springframework.beans.factory.BeanCreationException: 
  Error creating bean with name 'jacksonFix': Injection of autowired dependencies failed; 
  nested exception is org.springframework.beans.factory.BeanCreationException: 
  Could not autowire method: public void com.acme.project.JacksonFix.setAnnotationMethodHandlerAdapter(org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter); 
  nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
  No qualifying bean of type [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]   
  found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Run Code Online (Sandbox Code Playgroud)

看起来这些指令适用于旧版本的Spring MVC,而我正在寻找一种简单的方法来使用最新的Spring Boot.

And*_*son 102

如果您使用的是Spring Boot 1.3,则可以通过application.properties以下方式配置序列化包含:

spring.jackson.serialization-inclusion=non_null
Run Code Online (Sandbox Code Playgroud)

在Jackson 2.7中进行更改后,Spring Boot 1.4使用了一个名为的属性spring.jackson.default-property-inclusion:

spring.jackson.default-property-inclusion=non_null
Run Code Online (Sandbox Code Playgroud)

请参阅Spring Boot文档中的" 自定义Jackson ObjectMapper "部分.

如果您使用的是早期版本的Spring Boot,那么在Spring Boot中配置序列化包含的最简单方法是声明您自己的,适当配置的Jackson2ObjectMapperBuilderbean.例如:

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.serializationInclusion(JsonInclude.Include.NON_NULL);
    return builder;
}
Run Code Online (Sandbox Code Playgroud)

  • 不推荐使用:在Jackson 2.7中弃用了ObjectMapper.setSerializationInclusion ...使用/sf/answers/3089658071/ spring.jackson.default-property-inclusion = non_null代替 (6认同)
  • 是.这个方法可以放在你的应用程序中的任何`@Configuration`类中.主要的`Application`类是一个很好的地方. (2认同)
  • 重要说明:Jackson2ObjectMapperBuilder类是spring-web组件的一部分,已在4.1.1版中添加. (2认同)
  • @Deprecated setSerializationInclusion (2认同)

Pre*_*ric 21

文档说明了几种方法.

如果要ObjectMapper完全替换默认值,请定义@Bean该类型并将其标记为@Primary.

定义@Bean类型Jackson2ObjectMapperBuilder将允许您自定义默认值ObjectMapperXmlMapper(分别用于MappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverter).

  • 如何在不替换默认的“ObjectMapper”的情况下做同样的事情?我的意思是保留默认值和自定义值。 (5认同)

Vij*_*van 21

我对这个问题的回答有点迟了,但将来某人可能会觉得这很有用.除了许多其他方法之外,下面的方法效果最好,我个人认为更适合Web应用程序.

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

 ... other configurations

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        builder.serializationInclusion(Include.NON_EMPTY);
        builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在最新版本中,您必须实现“WebMvcConfigurer” (3认同)

小智 21

在applicationproperties中可以配置很多东西.不幸的是,此功能仅在版本1.3中,但您可以添加到Config-Class中

@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
    jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
Run Code Online (Sandbox Code Playgroud)

[更新:您必须处理ObjectMapper,因为在build()运行配置之前调用了-method.]


sen*_*982 10

您可以在bootstrap类中添加以下方法,并用注释 @SpringBootApplication

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);

    objectMapper.registerModule(new JodaModule());

    return objectMapper;
}
Run Code Online (Sandbox Code Playgroud)


so-*_*ude 9

spring.jackson.serialization-inclusion=non_null 曾经为我们工作过

但是当我们将spring boot版本升级到1.4.2.RELEASE或更高版本时,它就停止了工作.

现在,另一个属性spring.jackson.default-property-inclusion=non_null正在发挥魔力.

事实上,serialization-inclusion已被弃用.这就是我的intellij对我的看法.

不推荐使用:在Jackson 2.7中不推荐使用ObjectMapper.setSerializationInclusion

因此,开始使用spring.jackson.default-property-inclusion=non_null替代


Jon*_*nik 6

我偶然发现了另一个解决方案,它非常好。

基本上,只执行提到的博客中的第 2 步,并将自定义 ObjectMapper 定义为 Spring @Component。(当我刚刚从步骤 3 中删除所有 AnnotationMethodHandlerAdapter 内容时,事情就开始工作了。)

@Component
@Primary
public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper() {
        setSerializationInclusion(JsonInclude.Include.NON_NULL); 
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
    }
}
Run Code Online (Sandbox Code Playgroud)

只要组件在 Spring 扫描的包中就可以工作。(@Primary在我的情况下使用不是强制性的,但为什么不明确说明。)

对我来说,与其他方法相比有两个好处:

  • 这更简单;我可以从 Jackson 扩展一个类,不需要了解高度特定于 Spring 的东西,比如Jackson2ObjectMapperBuilder.
  • 我想在我的应用程序的另一部分使用相同的 Jackson 配置来反序列化 JSON,这样就非常简单:new CustomObjectMapper()而不是 new ObjectMapper().


Kal*_*oni 5

当我尝试在 Spring Boot 2.0.6 中将 ObjectMapper 设为主要对象时,出现错误所以我修改了 Spring Boot 为我创建的那个

另请参阅/sf/answers/3396390791/

@Lazy
@Autowired
ObjectMapper mapper;

@PostConstruct
public ObjectMapper configureMapper() {
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

    mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
    mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

    SimpleModule module = new SimpleModule();
    module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
    module.addSerializer(LocalDate.class, new LocalDateSerializer());
    mapper.registerModule(module);

    return mapper;
}
Run Code Online (Sandbox Code Playgroud)