提问人:Jonik 提问时间:2/4/2015 最后编辑:M. JustinJonik 更新时间:12/16/2022 访问量:221417
如何自定义Spring Boot隐式使用的Jackson JSON映射器?
How to customise the Jackson JSON mapper implicitly used by Spring Boot?
问:
我正在使用 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 一起使用。
答:
该文档说明了几种执行此操作的方法。
如果要完全替换默认值,请定义该类型的 a 并将其标记为 。
ObjectMapper
@Bean
@Primary
定义 of type 将允许您自定义 default 和 (分别用于 和 )。
@Bean
Jackson2ObjectMapperBuilder
ObjectMapper
XmlMapper
MappingJackson2HttpMessageConverter
MappingJackson2XmlHttpMessageConverter
评论
ObjectMapper
您可以通过以下方式配置属性包含和许多其他设置:application.properties
spring.jackson.default-property-inclusion=non_null
文档中有一个表,其中列出了可以使用的所有属性。
如果想要更多控制,还可以使用 bean 以编程方式自定义 Spring Boot 的配置,如文档中所述:Jackson2ObjectMapperBuilderCustomizer
上下文可以由一个或多个 bean 自定义。可以订购此类定制器 bean(Boot 自己的定制器的顺序为 0),允许在 Boot 的定制之前和之后应用其他定制。
Jackson2ObjectMapperBuilder
Jackson2ObjectMapperBuilderCustomizer
最后,如果您不想要任何 Boot 的配置,并且想要完全控制 Bean 的配置方式,请声明您自己的 bean:ObjectMapper
Jackson2ObjectMapperBuilder
@Bean
Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
// Configure the builder to suit your needs
return builder;
}
评论
@ComponentScan
@EnableAutoConfiguration
@Configuration
Application
我偶然发现了另一种解决方案,这非常好。
基本上,只执行上面提到的博客中的步骤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()
评论
ObjectMapper
@RestController
我对这个问题的回答有点晚,但将来有人可能会发现这很有用。除了许多其他方法之外,下面的方法效果最好,我个人认为更适合 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()));
}
}
评论
WebMvcConfigurer
可以在 applicationproperties 中配置很多东西。不幸的是,此功能仅在 1.3 版中,但您可以添加 Config-Class
@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
[更新:您必须在 ObjectMapper 上工作,因为在运行配置之前调用了 -method。build()
评论
我找到了上面描述的解决方案:
spring.jackson.serialization-inclusion=non_null
仅从 Spring boot 的 1.4.0.RELEASE 版本开始工作。在所有其他情况下,该配置将被忽略。
我通过试验对 spring boot 示例“spring-boot-sample-jersey”的修改来验证这一点
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
我知道这个问题要求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();
}
您可以在 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;
}
评论
当我尝试在 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;
}
向 Spring Boot peconfigured ObjectMapper 添加更多配置的正确方法是定义 Jackson2ObjectMapperBuilderCustomizer。否则,您将覆盖您不希望丢失的 Springs 配置。
@Configuration
public class MyJacksonConfigurer implements Jackson2ObjectMapperBuilderCustomizer {
@Override
public void customize(Jackson2ObjectMapperBuilder builder) {
builder.deserializerByType(LocalDate.class, new MyOwnJsonLocalDateTimeDeserializer());
}
}
我看到了很多关于这个问题的问题。这就是在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;
...
}
删除默认转换器并添加自定义转换器:
@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 方法将删除默认情况下将安装的所有现有转换器。
希望它能帮助像我这样浪费了几个小时调试问题的人:)
有两种方法可以自定义杰克逊:-ObjectMapper
- 覆盖 Spring Boot 自动配置的默认行为
ObjectMapper
- 覆盖 以获得完整的控制权
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/
评论