Spring MVC Rest Controller @RequestBody解析
我有一个春天休息的Web应用程序,其中包含一个像下面的通用休息控制器。 杰森将对象序列化为JSON时,GET方法正常工作。 但是,当我尝试调用save方法时,RequestBody参数正在转换为LinkedHashMap,而不是由T泛型定义的类型。
@RestController
public abstract class CrudAPI<T extends Object, ID extends Serializable>{
@Transactional
@RequestMapping(method = RequestMethod.POST, consumes = "application/json")
public ResponseEntity<Void> save(@RequestBody T entity){
service.save(entity);
return new ResponseEntity(HttpStatus.CREATED);
}
}
JSON:
{
"id":null,
"version":null,
"name":"Copel",
"disabled":false,
"type":"P",
"labels":[
{
"id":null,
"version":null,
"name":"unidade consumidora"
}
]
}
我收到以下错误:
HTTP状态500 - 请求处理失败; 嵌套异常是org.springframework.beans.NotReadablePropertyException:bean类的无效属性'version'[java.util.LinkedHashMap]:在回退访问期间找不到属性字段!
Spring配置:
@Configuration
@Import(Application.class)
@EnableWebMvc
@ComponentScan(basePackages = {"br.com.doc2cloud"})
public class WebConfig extends WebMvcConfigurerAdapter implements WebApplicationInitializer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
private MappingJackson2HttpMessageConverter jacksonConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate5Module());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setDateFormat(new ISO8601DateFormat());
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
jacksonConverter.setObjectMapper(mapper);
return jacksonConverter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jacksonConverter());
super.configureMessageConverters(converters);
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("javax.servlet.jsp.jstl.fmt.localizationContext", "messages");
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncoding", characterEncodingFilter);
characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
}
}
我的代码有什么问题?
你在用哪个版本的杰克逊? 我升级到2.7.3,当使用泛型(我有一个基本控制器与公共逻辑保存,列表等),我有同样的问题。 回滚到2.6.5允许我继续使用我的泛型基类。 我还没有研究这个问题的原因,但回滚给我解决了。
我不认为你可以达到你想要的。 Java泛型机制只在编译时才起作用。 编译后,泛型类型将被擦除并被实际类型(您的案例中的Object
)所取代。 您的控制器无法理解您尝试解析JSON数据的类型。
你得到LinkedHashMap
的原因是Jackson在默认情况下将它用于“未知”类型。 典型的JSON数据实际上是一个键值映射,Jackson保留了属性排序 - 这就是为什么使用链接哈希映射。