【问题标题】:Is it possible to create a custom Jackson objectMapper for Spring without resorting to XML?是否可以在不借助 XML 的情况下为 Spring 创建自定义 Jackson objectMapper?
【发布时间】:2015-03-05 14:32:10
【问题描述】:

It's easy to create a custom ObjectMapper 用于 Spring,但配置需要 XML。我正在尝试减少 XML 配置的数量,这些配置实际上不会改变,而无需重新部署我的整个系统。

所以标题说明了一切——我可以使用注释或其他一些非 XML 方法告诉 Spring,“嘿,请使用我的自定义对象映射器”?


编辑:

这似乎不起作用

@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。

【问题讨论】:

  • 只创建一个并将其注册为一个bean?
  • @chrylis 我该怎么做?

标签: java spring jackson


【解决方案1】:

您始终可以按照Spring Docs 中提供的步骤进行操作。

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

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

因此,您可以像这样用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,您必须在@Configuration 类中声明@Bean,如Spring docs about Java-based container configuration 中所述。

【讨论】:

  • 我已在我的问题中添加了信息 - 我使用的是第一个示例,但它似乎不起作用。 camelCase 名称没有更改为camel_casejava.util.Date 和joda DateTime 都正常显示。
  • 您的@Configuration-class 是否在启动时被扫描?
  • 我不得不在我的 web.xml 中添加几行配置 - 在我的 @Configuration 类上并添加了 @ComponentScan(basePackages = com.mystuff)。它之前没有加载页面,但现在可以了,所以我认为它正在被扫描。
  • 在我的 mapper 函数中设置断点 - 它肯定会被命中。
  • spring 会自动使用我的 ObjectMapper 来转换对象,还是我必须在某个地方指定?
【解决方案2】:

这似乎是一个错误。 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);
}

【讨论】:

    猜你喜欢
    • 2014-02-23
    • 2014-06-17
    • 2021-08-14
    • 2011-01-21
    • 1970-01-01
    • 2011-07-12
    • 2018-08-14
    • 2011-05-08
    • 1970-01-01
    相关资源
    最近更新 更多