首页 > 解决方案 > 是否可以在 SpringBoot 中注册控制器特定的 ObjectMapper

问题描述

我们有一个用例,其中端点返回的 JSON 必须根据端点进行不同的序列化。是否可以注册两个单独的 ObjectMapper bean 并指定哪个用于特定控制器?例如,如果我定义了一个如下所示的自定义 objectmapper,我是否可以要求 Spring Boot 使用此映射器仅序列化 ControllerTwo 的返回对象,但使用 default/Primary objectmapper 序列化从 ContorllerOne 返回的对象?

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper mapper = builder.build();
        return mapper;
    }

    @Bean
    public ObjectMapper objectMapperCustom(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper mapper = builder.build();
        //customize mapper
        return mapper;
    }

    @RestController
    public class ControllerOne {

       @GetMapping("/personNew/{id}")
       public Person getMyClass() {
    
       }
    }

    @RestController
    public class ControllerTwo {

       @GetMapping("/personOld/{id}")
       public Person getMyClass() {
    
       }
    }

标签: spring-bootjackson

解决方案


截至 2021 年,未答复意味着仍然不可能(容易)为相同的媒体/对象/响应类型使用替代 ObjectMapper。IE

不,不可能(容易):

... 在 SpringBoot 中注册控制器特定的 ObjectMapper

(..不是没有“重新实现”一半的)。

但是什么(容易的)可能的:

是为每个 java 和媒体类型注册自定义 (组合!+ 媒体类型的通配符)!(除了弹簧配置的“默认对象映射器”)ObjectMapper

和:

//no bean
private ObjectMapper fooMapper() {
    return new ObjectMapper()
            .configure(SerializationFeature.WRAP_ROOT_VALUE, true)
            .configure(SerializationFeature.INDENT_OUTPUT, false)
            .setDateFormat(new SimpleDateFormat("dd.MM.yyyy hh:mm:ss"));
}

//no bean
private ObjectMapper barMapper() {
    return new ObjectMapper()
            .configure(SerializationFeature.WRAP_ROOT_VALUE, true)
            .configure(SerializationFeature.INDENT_OUTPUT, false)
            .setDateFormat(new SimpleDateFormat("MM/dd/yyyy K:mm:ss a"));
}

我们可以做的:

@Bean //overwrites the autoconfigured 
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
     @Autowired ObjectMapper objectMapper // auto- and property configured, when no (alternative) ObjectMapper bean is defined.
) { 
    MappingJackson2HttpMessageConverter bean = new MappingJackson2HttpMessageConverter();
    // set "the default":
    bean.setObjectMapper(objectMapper);

    // register custom:
    bean.registerObjectMappersForType(Foo.class, m -> { //!!
        m.put(MediaType.APPLICATION_JSON, fooMapper());
        // ...
    });
    bean.registerObjectMappersForType(Bar.class, m -> {
        m.put(MediaType.APPLICATION_JSON, barMapper());
    });
    return bean;
}

这里的技巧不是(直接)管理对象映射器,而是注册“普通映射器”,因为spring.jackson.*一旦存在ObjectMapper bean,所有“魔法”都将被跳过。


为了实现 (eg) 的自定义“视图” Person引入了 (2014) JSON Views


推荐阅读