如何编写自定义转换以接收使用@RequestBody 注释的数据
How to write a custom convertor for recieving data annotated with @RequestBody
我正在尝试编写自定义转换器以接收数据 POSTed 到 REST 应用程序。我要填充的对象已经有它自己的接受字符串 JSON 的构建器,所以我必须使用它而不是 Jackson 反序列化器 Spring 通常使用的
我尝试了很多不同的方法,但我不断收到以下异常:
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class xxx.yyy.zzz.MyType]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `xxx.yyy.zzz.MyType` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (PushbackInputStream); line: 1, column: 1]
at at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:281) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:250) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
我的转换器看起来像:
public class MyConverter extends AbstractHttpMessageConverter<MyType> {
public MyConverter() {
super(/*MediaType.TEXT_PLAIN*/ MediaType.APPLICATION_JSON);
}
@Override
protected boolean supports(Class<?> type) {
return MyType.class.isAssignableFrom(type);
}
@Override
protected MyType readInternal(Class<? extends MyType> type, HttpInputMessage inputMessage) throws IOException {
String str = ..... read data from inputMessage
return MyType.build(str);
}
@Override
protected void writeInternal(MyType s, HttpOutputMessage outputMessage) {
}
}
控制器是:
@RequestMapping(method = RequestMethod.POST)
public void add(@RequestBody MyType data) {
System.out.println("add:" + data.toString());
}
即使将 MyConverter 的构造函数中的 MediaType 更改为 'MediaType.ALL',它仍然会失败。奇怪的是,如果我将其更改为 TEXT_PLAIN 和 POST,并将 Content-Type 设置为 'text/plain',它会起作用!
回答我自己的问题。问题出在处理 HttpMessageConverter 对象的顺序上。在我的转换器有机会之前,内置转换器正在处理中,但失败了。
这不是最好的代码,但它有效:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(@Nonnull List<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> temp = new ArrayList<>();
temp.add(new MyConverter());
temp.addAll(converters);
converters.clear();
converters.addAll(temp);
}
}
我不太相信这是我认为应该是一个相当标准的问题的最佳答案。如果有人可以提出更好的答案,我会很乐意接受
我正在尝试编写自定义转换器以接收数据 POSTed 到 REST 应用程序。我要填充的对象已经有它自己的接受字符串 JSON 的构建器,所以我必须使用它而不是 Jackson 反序列化器 Spring 通常使用的
我尝试了很多不同的方法,但我不断收到以下异常:
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class xxx.yyy.zzz.MyType]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `xxx.yyy.zzz.MyType` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (PushbackInputStream); line: 1, column: 1]
at at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:281) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:250) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
我的转换器看起来像:
public class MyConverter extends AbstractHttpMessageConverter<MyType> {
public MyConverter() {
super(/*MediaType.TEXT_PLAIN*/ MediaType.APPLICATION_JSON);
}
@Override
protected boolean supports(Class<?> type) {
return MyType.class.isAssignableFrom(type);
}
@Override
protected MyType readInternal(Class<? extends MyType> type, HttpInputMessage inputMessage) throws IOException {
String str = ..... read data from inputMessage
return MyType.build(str);
}
@Override
protected void writeInternal(MyType s, HttpOutputMessage outputMessage) {
}
}
控制器是:
@RequestMapping(method = RequestMethod.POST)
public void add(@RequestBody MyType data) {
System.out.println("add:" + data.toString());
}
即使将 MyConverter 的构造函数中的 MediaType 更改为 'MediaType.ALL',它仍然会失败。奇怪的是,如果我将其更改为 TEXT_PLAIN 和 POST,并将 Content-Type 设置为 'text/plain',它会起作用!
回答我自己的问题。问题出在处理 HttpMessageConverter 对象的顺序上。在我的转换器有机会之前,内置转换器正在处理中,但失败了。
这不是最好的代码,但它有效:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(@Nonnull List<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> temp = new ArrayList<>();
temp.add(new MyConverter());
temp.addAll(converters);
converters.clear();
converters.addAll(temp);
}
}
我不太相信这是我认为应该是一个相当标准的问题的最佳答案。如果有人可以提出更好的答案,我会很乐意接受