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

How to customise the Jackson JSON mapper implicitly used by Spring Boot?

提问人:Jonik 提问时间:2/4/2015 最后编辑:M. JustinJonik 更新时间:12/16/2022 访问量:221417

问:

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

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

如上所述,Spring MVC 隐式使用 Jackson 将我的对象序列化为 JSON。EventList

但我想对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 一起使用。

java spring-mvc 杰克逊 spring-boot

评论

0赞 sven.kwiotek 2/4/2015
你插入了这个注释吗?: @SuppressWarnings({“SpringJavaAutowiringInspection”})
0赞 Constantino Cronemberger 2/19/2019
请注意,如果您也使用 Spring Web,则需要手动告诉它使用此 ObjectMapper,否则它将创建自己的实例,该实例不会被配置。查看 stackoverflow.com/questions/7854030/...

答:

27赞 Predrag Maric 2/4/2015 #1

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

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

定义 of type 将允许您自定义 default 和 (分别用于 和 )。@BeanJackson2ObjectMapperBuilderObjectMapperXmlMapperMappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverter

评论

9赞 soufrk 5/22/2018
如何在不替换默认值的情况下做同样的事情?我的意思是保持默认值和习惯。ObjectMapper
136赞 Andy Wilkinson 2/4/2015 #2

您可以通过以下方式配置属性包含和许多其他设置:application.properties

spring.jackson.default-property-inclusion=non_null

文档中有一个表,其中列出了可以使用的所有属性。

如果想要更多控制,还可以使用 bean 以编程方式自定义 Spring Boot 的配置,如文档中所述:Jackson2ObjectMapperBuilderCustomizer

上下文可以由一个或多个 bean 自定义。可以订购此类定制器 bean(Boot 自己的定制器的顺序为 0),允许在 Boot 的定制之前和之后应用其他定制。Jackson2ObjectMapperBuilderJackson2ObjectMapperBuilderCustomizer

最后,如果您不想要任何 Boot 的配置,并且想要完全控制 Bean 的配置方式,请声明您自己的 bean:ObjectMapperJackson2ObjectMapperBuilder

@Bean
Jackson2ObjectMapperBuilder objectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    // Configure the builder to suit your needs
    return builder;
}

评论

1赞 Jonik 2/5/2015
好吧,这似乎有效。你会把这样的方法放在哪里?也许在主 Application 类中(带有 等)?@ComponentScan@EnableAutoConfiguration
2赞 Andy Wilkinson 2/5/2015
是的。此方法可以用于应用中的任何类。主班是它的好地方。@ConfigurationApplication
3赞 gaoagong 5/30/2015
重要说明:Jackson2ObjectMapperBuilder 类是 spring-web 组件的一部分,是在版本 4.1.1 中添加的。
2赞 Dimitri Kopriwa 8/15/2016
@Deprecated setSerializationInclusion
6赞 so-random-dude 5/23/2017
已弃用:ObjectMapper.setSerializationInclusion 在 Jackson 2.7 中已弃用 ...请改用 stackoverflow.com/a/44137972/6785908 spring.jackson.default-property-inclusion=non_null
7赞 Jonik 2/5/2015 #3

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

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

@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()

评论

1赞 Andy Wilkinson 2/5/2015
这种方法的缺点是,您的自定义配置不会应用于 Spring Boot 创建或配置的任何实例。ObjectMapper
0赞 Jonik 2/5/2015
嗯,自定义配置用于类中的隐式序列化,目前对我来说就足够了。(所以你的意思是这些实例是由Spring MVC创建的,而不是Spring Boot?但是,如果我遇到其他需要实例化 ObjectMappers 的情况,我会牢记 Jackson2ObjectMapperBuilder 方法!@RestController
32赞 vvra 6/12/2015 #4

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

评论

5赞 João Pedro Schmitt 2/1/2020
在最新版本中,您必须实现WebMvcConfigurer
0赞 Somal Somalski 6/5/2020
是的,人们,试试这个解决方案,我尝试为 ObjectMapper 提供 Bean,然后为 Jackson2ObjectMapperBuilder 提供 Bean,但没有用,但我仍然不知道为什么。附加封面起作用了!
24赞 nbank 10/2/2015 #5

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

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

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

评论

0赞 Nestor Milyaev 8/16/2017
这是挽救我一天的解决方案。除了我确实将此方法添加到REST控制器本身,而不是配置类中。
1赞 Tim Dugan 8/13/2016 #6

我找到了上面描述的解决方案:

spring.jackson.serialization-inclusion=non_null

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

我通过试验对 spring boot 示例“spring-boot-sample-jersey”的修改来验证这一点

11赞 so-random-dude 5/23/2017 #7

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

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

现在,另一家酒店正在施展魔力。spring.jackson.default-property-inclusion=non_null

事实上,已弃用。这就是我的 intellij 扔给我的东西。serialization-inclusion

已弃用:ObjectMapper.setSerializationInclusion 已弃用 杰克逊 2.7

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

0赞 Sam YC 10/19/2017 #8

我知道这个问题要求Spring boot,但我相信很多人都在寻找如何在非Spring boot中做到这一点,就像我一样几乎整天都在搜索。

在 Spring 4 以上,如果您只打算配置 ,则无需配置。MappingJacksonHttpMessageConverterObjectMapper

你只需要做:

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();
}
14赞 sendon1982 9/26/2018 #9

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

评论

0赞 Richtopia 3/21/2019
这个使用 Boot 2.1.3 对我有用。spring.jackson 属性没有影响。
5赞 Kalpesh Soni 5/16/2019 #10

当我尝试在 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;
}
3赞 Michael 11/21/2020 #11

向 Spring Boot peconfigured ObjectMapper 添加更多配置的正确方法是定义 Jackson2ObjectMapperBuilderCustomizer。否则,您将覆盖您不希望丢失的 Springs 配置。

 @Configuration
public class MyJacksonConfigurer implements Jackson2ObjectMapperBuilderCustomizer {
    @Override
    public void customize(Jackson2ObjectMapperBuilder builder) {
        builder.deserializerByType(LocalDate.class, new MyOwnJsonLocalDateTimeDeserializer());
    }
}
1赞 Patrick Mutwiri 3/9/2022 #12

我看到了很多关于这个问题的问题。这就是在Spring Boot版本2.7.0-SNAPSHOT中对我有用的东西。

我创建了一个配置 MapperConfigs,创建了一个 objectMapper bean,如文档所述注释了 primary

@Configuration
@Log4j2
public class MapperConfigs {
    @Bean
    @Primary
    ObjectMapper objectMapper() {
        log.info("Object mapper overrides ");
        return JsonMapper.builder()
                .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .build();
    }
}

然后我@Autowired objectMapper。见下文:

@Service
public class GenerateRequestUniqueID {
    @Autowired
    ObjectMapper objectMapper;
    ...
}
0赞 Mohan 8/25/2022 #13

删除默认转换器并添加自定义转换器:

@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//        Remove the default MappingJackson2HttpMessageConverter
        converters.removeIf(converter -> {
            String converterName = converter.getClass().getSimpleName();
            return converterName.equals("MappingJackson2HttpMessageConverter");
        });
//        Add your custom MappingJackson2HttpMessageConverter
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        converter.setObjectMapper(objectMapper);
        converters.add(converter);
        WebMvcConfigurer.super.extendMessageConverters(converters);
    }
}

注意:请不要使用 WebMvcConfigurer 中的 configureMessageConverters() 而不是 extendMessageConverters(),因为 configure 方法将删除默认情况下将安装的所有现有转换器。

希望它能帮助像我这样浪费了几个小时调试问题的人:)

0赞 Ashish Lahoti 12/16/2022 #14

有两种方法可以自定义杰克逊:-ObjectMapper

  1. 覆盖 Spring Boot 自动配置的默认行为ObjectMapper
  2. 覆盖 以获得完整的控制权ObjectMapper

覆盖 ObjectMapper

@Configuration
public class CustomJacksonConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        return builder.build().setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
                .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .configure(SerializationFeature.INDENT_OUTPUT, true)
                .registerModule(new JavaTimeModule());
    }
}

覆盖 ObjectMapper

@Configuration
public class CustomJacksonConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
                .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .configure(SerializationFeature.INDENT_OUTPUT, true);
    }
}

来源: https://codingnconcepts.com/spring-boot/customize-jackson-json-mapper/