Spring Boot:请求和响应的不同ObjectMapper实例

时间:2017-03-09 09:23:59

标签: java spring spring-boot jackson

我的春季启动应用程序中有以下控制器:

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

MyClass有一个字段,让我们说“myField&#39;我希望对此字段的请求和响应有不同的NamingStrategy配置(这是因为我不想为一个字段创建一个新类)。我已将ObjectMapper实例配置如下:

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

这将用于请求和响应(即反序列化和序列化),春季启动中是否有任何方法可以指示控制器使用不同的ObjectMapper实例?

3 个答案:

答案 0 :(得分:2)

您可以使用 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标头。当然,您可以使用任何其他名称作为所需的内容类型,显示的名称只是一个示例。

答案 1 :(得分:0)

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

但是找到一种明确定制spring object mapper的方法会更好。

答案 2 :(得分:0)

您可以在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);

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