是否可以在不求助于 XML 的情况下为 Spring 创建自定义 Jackson objectMapper?
Is it possible to create a custom Jackson objectMapper for Spring without resorting to XML?
It's easy to create a custom ObjectMapper 为 Spring,但配置需要 XML。我正在尝试减少 XML 配置的数量,这些东西确实不会改变,而无需重新部署我的整个系统。
所以标题说明了一切 - 我可以使用注释或其他一些 non-XML 方法来告诉 Spring、"Hey, please use my custom object mapper pls" 吗?
编辑:
这似乎不起作用
@Configuration
@EnableWebMvc
public class AppConfig {
@Primary
@Bean
public ObjectMapper mapper(){
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
mapper.registerModule(new JodaModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
编辑 2:
我不相信 Spring 正在使用 my ObjectMapper。我有这个代码:
@Primary
@Bean
public ObjectMapper mapper(){
ObjectMapper mapper = new ObjectMapper();
JodaModule mod = new JodaModule();
mod.addSerializer(DateTime.class, new JsonSerializer<DateTime>() {
@Override
public void serialize(DateTime dateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
System.out.println("Hi, bob");
}
});
mapper.registerModule(mod);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
return mapper;
}
但是当我在 System.out.println("Hi, bob")
上设置断点时,它永远不会被调用 - 尽管我肯定是在序列化 DateTime。
您始终可以按照 Spring Docs 中提供的步骤进行操作。
If you want to replace the default ObjectMapper
completely, define a @Bean
of that type and mark it as @Primary
.
Defining a @Bean
of type Jackson2ObjectMapperBuilder
will allow you to customize both default ObjectMapper
and XmlMapper
(used in MappingJackson2HttpMessageConverter
and MappingJackson2XmlHttpMessageConverter
respectively).
所以,要么你用你的 ObjectMapper
定义一个 @Bean
像这样:
@Primary
@Bean
public ObjectMapper mapper() {
// Customize...
return new ObjectMapper().setLocale(Locale.UK);
}
或者,您定义 Jackson2ObjectMapperBuilder
类型的 @Bean
并像这样自定义生成器:
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
// Customize
builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
return builder;
}
This blog entry 进一步描述自定义。
为了使用 @Bean
注释注册 bean,您必须按照 Spring docs about Java-based container configuration 中的描述在 @Configuration
class 中声明 @Bean
。 =32=]
这似乎是一个错误。 Spring 引导文档说用@Primary 注释 ObjectMapper Bean 应该使 Spring 上下文使用它而不是 Spring 的默认映射器。但是,这似乎不起作用。我找到了不使用 XML.
的解决方法
//Since Spring won't use the custom object mapper Bean defined below for
//HTTP message conversion(eg., when a Java object is returned from a controller,
//and should be converted to json using Jackson), we must override this method
//and tell it to use a custom message converter. We configure that custom converter
//below to use our customized Object mapper.
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
}
//configures the converter to use our custom ObjectMapper
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
//this line here
jsonConverter.setObjectMapper(objectMapper());
return jsonConverter;
}
//Primary annotation tells the Spring container to use this
//mapper as the primary mapper, instead of
//the Spring's defaultly configured mapper. Primary annotation
// DOESN'T work for some reason(this is most likely a bug and will be resolved in the future.
// When resolved, this Bean will be all it takes to tell Spring to use this ObjectMapper everywhere)
// That means that there won't be a need to configure the Http message converters manually(see method above).
@Primary
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
configureObjectMapper(mapper);
return mapper;
}
//configure ObjectMapper any way you'd like
//This configuration tells the ObjectMapper to
//(de)serialize all fields(private,protected,public,..) of all objects
//and to NOT (de)serialize any properties(getters,setters).
private void configureObjectMapper(ObjectMapper mapper) {
//properties for jackson are fields with getters and setters
//sets all properties to NOT be serialized or deserialized
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
//tell the mapper to traverse all fields and not only default
//default=public fields + fields with getters and setters
//set all fields to be serialized and deserialized
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
}
It's easy to create a custom ObjectMapper 为 Spring,但配置需要 XML。我正在尝试减少 XML 配置的数量,这些东西确实不会改变,而无需重新部署我的整个系统。
所以标题说明了一切 - 我可以使用注释或其他一些 non-XML 方法来告诉 Spring、"Hey, please use my custom object mapper pls" 吗?
编辑:
这似乎不起作用
@Configuration
@EnableWebMvc
public class AppConfig {
@Primary
@Bean
public ObjectMapper mapper(){
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
mapper.registerModule(new JodaModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
编辑 2: 我不相信 Spring 正在使用 my ObjectMapper。我有这个代码:
@Primary
@Bean
public ObjectMapper mapper(){
ObjectMapper mapper = new ObjectMapper();
JodaModule mod = new JodaModule();
mod.addSerializer(DateTime.class, new JsonSerializer<DateTime>() {
@Override
public void serialize(DateTime dateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
System.out.println("Hi, bob");
}
});
mapper.registerModule(mod);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
return mapper;
}
但是当我在 System.out.println("Hi, bob")
上设置断点时,它永远不会被调用 - 尽管我肯定是在序列化 DateTime。
您始终可以按照 Spring Docs 中提供的步骤进行操作。
If you want to replace the default
ObjectMapper
completely, define a@Bean
of that type and mark it as@Primary
.Defining a
@Bean
of typeJackson2ObjectMapperBuilder
will allow you to customize both defaultObjectMapper
andXmlMapper
(used inMappingJackson2HttpMessageConverter
andMappingJackson2XmlHttpMessageConverter
respectively).
所以,要么你用你的 ObjectMapper
定义一个 @Bean
像这样:
@Primary
@Bean
public ObjectMapper mapper() {
// Customize...
return new ObjectMapper().setLocale(Locale.UK);
}
或者,您定义 Jackson2ObjectMapperBuilder
类型的 @Bean
并像这样自定义生成器:
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
// Customize
builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
return builder;
}
This blog entry 进一步描述自定义。
为了使用 @Bean
注释注册 bean,您必须按照 Spring docs about Java-based container configuration 中的描述在 @Configuration
class 中声明 @Bean
。 =32=]
这似乎是一个错误。 Spring 引导文档说用@Primary 注释 ObjectMapper Bean 应该使 Spring 上下文使用它而不是 Spring 的默认映射器。但是,这似乎不起作用。我找到了不使用 XML.
的解决方法//Since Spring won't use the custom object mapper Bean defined below for
//HTTP message conversion(eg., when a Java object is returned from a controller,
//and should be converted to json using Jackson), we must override this method
//and tell it to use a custom message converter. We configure that custom converter
//below to use our customized Object mapper.
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
}
//configures the converter to use our custom ObjectMapper
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
//this line here
jsonConverter.setObjectMapper(objectMapper());
return jsonConverter;
}
//Primary annotation tells the Spring container to use this
//mapper as the primary mapper, instead of
//the Spring's defaultly configured mapper. Primary annotation
// DOESN'T work for some reason(this is most likely a bug and will be resolved in the future.
// When resolved, this Bean will be all it takes to tell Spring to use this ObjectMapper everywhere)
// That means that there won't be a need to configure the Http message converters manually(see method above).
@Primary
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
configureObjectMapper(mapper);
return mapper;
}
//configure ObjectMapper any way you'd like
//This configuration tells the ObjectMapper to
//(de)serialize all fields(private,protected,public,..) of all objects
//and to NOT (de)serialize any properties(getters,setters).
private void configureObjectMapper(ObjectMapper mapper) {
//properties for jackson are fields with getters and setters
//sets all properties to NOT be serialized or deserialized
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
//tell the mapper to traverse all fields and not only default
//default=public fields + fields with getters and setters
//set all fields to be serialized and deserialized
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
}