是否可以在不诉诸XML的情况下为Spring创建自定义Jackson objectMapper?

时间:2015-03-05 14:32:11

标签: java spring jackson

对于Spring,

It's easy to create a custom ObjectMapper,但配置需要XML。我试图在不需要重新部署整个系统的情况下减少真正无法改变的事情的XML配置量。

所以标题说明了一切 - 我可以使用注释或其他非XML方法来告诉Spring,"嘿,请使用我的自定义对象映射器和#34;?


修改

这似乎不起作用

@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正在使用我的 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。

2 个答案:

答案 0 :(得分:3)

您始终可以按照Spring Docs

中提供的步骤操作
  

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

     

定义@Bean类型Jackson2ObjectMapperBuilder,您可以自定义默认ObjectMapperXmlMapper(分别用于MappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverter )。

因此,您可以使用@Bean定义ObjectMapper,如下所示:

@Primary
@Bean
public ObjectMapper mapper() {
    // Customize...
    return new ObjectMapper().setLocale(Locale.UK);
}

或者,您定义类型@Bean的{​​{1}}并按照以下方式自定义构建器:

Jackson2ObjectMapperBuilder

This blog entry进一步描述了自定义。

要使用@Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); // Customize builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd")); return builder; } 注释注册bean,您必须按照Spring docs about Java-based container configuration中的说明在@Bean类中声明@Bean

答案 1 :(得分:3)

这似乎是一个错误。 Spring Boot文档说使用@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);
}