【问题标题】:Spring Boot : Different ObjectMapper instances for Request and ResponseSpring Boot:请求和响应的不同 ObjectMapper 实例
【发布时间】:2017-07-30 04:55:07
【问题描述】:

我的 Spring Boot 应用程序中有以下控制器:

@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<ResponseDto<MyClass> process(@RequestBody RequestDto<MyClass> request){
    return null;
}

MyClass 有一个字段,比方说“myField”,我想要不同的NamingStrategyconfiguration 用于该字段的请求和响应(这是因为我不想只为一个字段创建一个新类)。我已将ObjectMapper 实例配置如下:

@Bean
public ObjectMapper objectMapper(){
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setPropertyNamingStrategy(namingStrategy);
    return objectMapper;
}

这将用于请求和响应(即反序列化和序列化),在 spring boot 中有什么方法可以指示控制器使用不同的ObjectMapper 实例?

【问题讨论】:

标签: java spring spring-boot jackson


【解决方案1】:

您可以通过 content negotiation 解决它。首先,定义您的自定义 HttpMessageConverter。在以下示例中,我定义了一个自定义转换器,当请求 Content-Type 标头设置为 application/test+json 时应用该转换器:

@Bean
public HttpMessageConverters customConverters() {
    final AbstractJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(new ObjectMapper());
    converter.setSupportedMediaTypes(Collections.singletonList(MediaType.valueOf("application/test+json")));

    return new HttpMessageConverters(true, Collections.singletonList(converter));
}

为简单起见,我使用了新创建的 ObjectMapper - 在您的情况下,您必须在此处传递以前配置的对象。

接下来是告诉您的操作只接受 appliction/test+json 请求(请记住,从现在开始,它需要 Content-Type:application/test+json 标头出现在对该端点的每个请求中):

@RequestMapping(method = RequestMethod.POST, consumes = "application/test+json")
public ResponseEntity<ResponseDto<MyClass> process(@RequestBody RequestDto<MyClass> request){
    return null;
}

最后一件事是确保当您调用此端点时,Content-Type:application/test+json 标头已设置。当然,您可以为所需的内容类型使用任何其他名称,提供的名称只是一个示例。

【讨论】:

    【解决方案2】:

    您可以在 ObjectMapper 中使用反序列化修饰符通过模块在对象反序列化时覆盖启用的功能集。这个应该可以解决问题:

        public class FeatureModifyingBeanDeserializerModifier extends BeanDeserializerModifier {
    
            private Collection<Class<?>> modifiedClasses;
    
            public FeatureModifyingBeanDeserializerModifier(Collection<Class<?>> modifiedClasses) {
                this.modifiedClasses = Collections.unmodifiableSet(new HashSet<Class<?>>(modifiedClasses));
            }
    
            @Override
            public JsonDeserializer<?> modifyDeserializer(
                    DeserializationConfig config, BeanDescription beanDesc, final JsonDeserializer<?> deserializer) {
                JsonDeserializer<?> result = deserializer;
                Class<?> beanClass = beanDesc.getBeanClass();
    
                if (modifiedClasses.contains(beanClass)) {
                    result = new FeatureModifyingStdDeserializer(deserializer, beanClass);
                }
                return result;
            }
    
            private static class FeatureModifyingStdDeserializer extends StdDeserializer<Object> {
    
                private JsonDeserializer<?> deserializer;
    
                private FeatureModifyingStdDeserializer(
    JsonDeserializer<?> deserializer, Class<?> beanClass) {
                    super(beanClass);
                    this.deserializer = deserializer;
                }
    
                @Override
                public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                    p.enable(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER);
                    return deserializer.deserialize(p, ctxt);
                }
            }      
        }
    

    您必须将其注册为 ObjectMapper 的模块,如下所示:

    ObjectMapper objectMapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    
    module.setDeserializerModifier(new FeatureModifyingBeanDeserializerModifer(Arrays.asList(Journey.class)));
    objectMapper.registerModule(module);
    

    对于序列化,您可以向 Journey 类添加一个 @JsonSerialize 注释,并以您想要的任何方式对其进行序列化。如果您需要编写未转义的字符串,您可以使用 JsonGenerator 中的 writeRaw。

    【讨论】:

      【解决方案3】:

      一个肮脏的技巧:您可以为 MyClass 编写自定义序列化器和反序列化器,在那里您明确使用两个单独的对象映射器,一个用于序列化(用于响应),第二个用于反序列化(用于请求)。

      但最好是想办法显式自定义spring object mapper。

      【讨论】:

        猜你喜欢
        • 2017-03-07
        • 1970-01-01
        • 2016-05-17
        • 1970-01-01
        • 1970-01-01
        • 2019-03-26
        • 2023-02-06
        • 2019-07-17
        • 2019-10-17
        相关资源
        最近更新 更多