[英]Spring Boot : Different ObjectMapper instances for Request and Response
I have following controller in my spring boot application: 我的Spring Boot应用程序中有以下控制器:
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<ResponseDto<MyClass> process(@RequestBody RequestDto<MyClass> request){
return null;
}
MyClass
has a field, let's say 'myField' and I want different NamingStrategy
configuration for request and response for this field (this is because I don't want to create a new class just for one field). MyClass
有一个字段,比方说'myField',我想要该字段的请求和响应使用不同的NamingStrategy
配置(这是因为我不想只为一个字段创建一个新类)。 I have configured ObjectMapper
instance as below: 我已经配置了
ObjectMapper
实例,如下所示:
@Bean
public ObjectMapper objectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(namingStrategy);
return objectMapper;
}
This will be used both for Request and Response (ie deserialization and serialization), is there any way in spring boot by which I can instruct the controller to use different ObjectMapper
instances? 这将用于请求和响应(即反序列化和序列化),在Spring Boot中有什么方法可以指示控制器使用不同的
ObjectMapper
实例?
You can solve it with content negotiation . 您可以通过内容协商解决它。 Firstly, define your custom HttpMessageConverter .
首先,定义您的自定义HttpMessageConverter 。 In following example I have defined a custom converter that is applied when the request
Content-Type
header is set to application/test+json
: 在以下示例中,我定义了一个自定义转换器,当请求
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));
}
For simplicity of this example I've used newly created ObjectMapper
- in your case you will have to pass here previously configured object. 为了简化本示例,我使用了新创建的
ObjectMapper
在您的情况下,您将必须在此处传递先前配置的对象。
Next thing is to tell your action to accept only appliction/test+json
requests (keep in mind, that from now on it requires to Content-Type:application/test+json
header to present in every request to this endpoint): 接下来的事情是告诉您的操作仅接受
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;
}
Last thing is to make sure that when you call this endpoint, Content-Type:application/test+json
header is set. 最后一件事是确保在调用此终结点时,设置了
Content-Type:application/test+json
标头。 Of course you can use any other name for desired content type, presented name is just an example. 当然,您可以将其他任何名称用于所需的内容类型,显示名称仅是示例。
You can use a deserialization modifier in your ObjectMapper to override the set of enabled features at object deserialization time via a module. 您可以在ObjectMapper中使用反序列化修饰符,以在对象反序列化时通过模块覆盖已启用的功能集。 This one should do the trick:
这应该可以解决问题:
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);
}
}
}
You have to register it with the ObjectMapper as a module like this: 您必须将其注册到ObjectMapper作为如下模块:
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new FeatureModifyingBeanDeserializerModifer(Arrays.asList(Journey.class)));
objectMapper.registerModule(module);
For serialization, you can add an @JsonSerialize annotation to the Journey class and serialize it in whatever way you want. 对于序列化,您可以向Journey类添加@JsonSerialize批注,并以所需的任何方式对其进行序列化。 If you need to write an unescaped string you can use writeRaw from JsonGenerator.
如果需要编写未转义的字符串,则可以使用JsonGenerator中的writeRaw。
One dirty hack: you may write custom serializer and deserializer for MyClass, there you explicitly use two separate object mapper one for serialization (for response) and second for deserialization (for request). 一个肮脏的技巧:您可以为MyClass编写自定义序列化器和反序列化器,在那里您显式使用两个单独的对象映射器,一个用于序列化(用于响应),第二个用于反序列化(用于请求)。
But it's better to find a way to explicitly customize spring object mapper. 但是最好找到一种显式自定义spring对象映射器的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.