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


101

我正在使用Spring Boot(1.2.1),其方式与他们的Build RESTful Web Service教程中的方式类似:

@RestController
public class EventController {

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

}

因此,在上面,Spring MVC隐式使用Jackson将我的EventList对象序列化为JSON。

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

setSerializationInclusion(JsonInclude.Include.NON_NULL)

问题是,定制隐式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: {}

看起来这些说明适用于旧版本的Spring MVC,而我正在寻找一种简单的方法来使此版本与最新的Spring Boot一起使用。


您是否插入了此注释?:@SuppressWarnings({“ SpringJavaAutowiringInspection”})
sven.kwiotek 2015年

请注意,如果您还使用Spring Web,则需要手动告诉它使用此ObjectMapper,否则它将创建自己的实例,该实例将不会配置。看到 stackoverflow.com/questions/7854030/...
康斯坦丁诺Cronemberger

Answers:


116

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

spring.jackson.serialization-inclusion=non_null

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

spring.jackson.default-property-inclusion=non_null

请参阅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;
}

1
好吧,这似乎可行。您将在哪里放置这种方法?也许在主Application类中(带有@ComponentScan@EnableAutoConfiguration等等)?
尼克2015年

2
是。此方法可以@Configuration在应用程序的任何类中使用。主Application班是个好地方。
安迪·威尔金森

2
重要说明:Jackson2ObjectMapperBuilder类是spring-web组件的一部分,并在版本4.1.1中添加。
gaoagong

2
@不建议使用setSerializationInclusion
Dimitri Kopriwa '16

6
不推荐使用:在Jackson 2.7中不推荐使用ObjectMapper.setSerializationInclusion ...使用stackoverflow.com/a/44137972/6785908 spring.jackson.default-property-inclusion = non_null代替
随机

24

我对这个问题的回答有点晚,但是将来有人会觉得这个有用。除许多其他方法外,下面的方法效果最好,我个人认为更适合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()));
    }
}

1
在最近的版本中,你必须实现WebMvcConfigurer
若奥·佩德罗·施密特

是的,人们,请尝试此解决方案,我尝试为Bean提供给ObjectMapper,然后为Bean提供给Jackson2ObjectMapperBuilder购买,但没有成功,我仍然不知道为什么。追加掩护有效!
Somal Somalski

23

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

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

[更新:您必须在ObjectMapper上工作,因为build()-method在配置运行之前被调用。]


那就是解决方案,拯救了我的一天。除非我确实将此方法添加到REST控制器本身,而不是添加到配置类。
Nestor Milyaev '17

20

该文档说明了执行此操作的几种方法。

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

定义a @Bean类型Jackson2ObjectMapperBuilder将允许您自定义default ObjectMapperXmlMapper(分别用于MappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverter)。


2
在不替换默认值的情况下该如何做ObjectMapper?我的意思是保持默认以及自定义。
soufrk

12

您可以在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;
}

这个使用Boot 2.1.3为我工作。spring.jackson属性无效。
Richtopia '19

9

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

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

现在,另一个财产 spring.jackson.default-property-inclusion=non_null正在发挥作用。

其实serialization-inclusion已经过时了。这就是我的智谋向我扔的东西。

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

因此,开始spring.jackson.default-property-inclusion=non_null改用


4

我偶然发现了另一个很好的解决方案。

基本上,仅从提到的博客中执行步骤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); 
    }
}

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

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

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

这种方法的缺点是您的自定义配置不会应用于ObjectMapperSpring Boot创建或配置的任何实例。
安迪·威尔金森

嗯,自定义配置用于隐式序列化@RestController类目前足以满足我。(因此,您的意思是这些实例是由Spring MVC创建的,而不是由Spring Boot创建的?)但是,如果遇到其他需要实例化ObjectMappers的情况,我将牢记Jackson2ObjectMapperBuilder方法!
尼克2015年

3

当我尝试在Spring Boot 2.0.6中使ObjectMapper成为主要对象时,出现错误,因此我修改了spring boot为我创建的对象

另请参阅https://stackoverflow.com/a/48519868/255139

@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;
}

1

我发现了上述解决方案:

spring.jackson.serialization-inclusion =非空

仅从1.4.0.RELEASE版本的Spring Boot开始工作。在所有其他情况下,配置将被忽略。

我通过尝试修改弹簧靴样品“ spring-boot-sample-jersey”来验证了这一点


0

我知道要求Spring Boot的问题,但是我相信很多人正在寻找如何在非Spring Boot中做到这一点,例如我几乎整天都在搜索。

在Spring 4之上,MappingJacksonHttpMessageConverter如果仅打算进行配置,则无需进行配置ObjectMapper

您只需要做:

public class MyObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 4219938065516862637L;

    public MyObjectMapper() {
        super();
        enable(SerializationFeature.INDENT_OUTPUT);
    }       
}

在您的Spring配置中,创建以下bean:

@Bean 
public MyObjectMapper myObjectMapper() {        
    return new MyObjectMapper();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.