简体   繁体   English

Spring MVC Rest Controller @RequestBody解析

[英]Spring MVC Rest Controller @RequestBody Parsing

I have a spring rest web app that contains aa generic rest controller like below. 我有一个spring rest网络应用程序,其中包含一个通用的rest控制器,如下所示。 The GET methods are working fine having Jackson serializing the objects to JSON. 杰克逊将对象序列化为JSON后,GET方法运行良好。 However when I try to call the save method, the RequestBody parameter is being converted to LinkedHashMap instead of the type defined by the T generic type. 但是,当我尝试调用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);
    }

}

The JSON: JSON:

{
   "id":null,
   "version":null,
   "name":"Copel",
   "disabled":false,
   "type":"P",
   "labels":[
      {
         "id":null,
         "version":null,
         "name":"unidade consumidora"
      }
   ]
}

I get the following error: 我收到以下错误:

HTTP Status 500 - Request processing failed; HTTP状态500-请求处理失败; nested exception is org.springframework.beans.NotReadablePropertyException: Invalid property 'version' of bean class [java.util.LinkedHashMap]: Could not find field for property during fallback access! 嵌套的异常是org.springframework.beans.NotReadablePropertyException:Bean类[java.util.LinkedHashMap]的无效属性“版本”:在回退访问期间找不到属性字段!

The Spring configuration: 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, "/*");
    }
}

What is wrong with my code? 我的代码有什么问题?

I don't think you can achieve what you want. 我认为您无法实现自己想要的。 Java generics mechanism works only in compile-time. Java泛型机制仅在编译时有效。 After compilation generic types are erased and are replaced by actual types ( Object in your case). 编译后,泛型类型将被擦除,并由实际类型替换(在您的情况下为Object )。 There is no way your controller will understand to what type you try to parse JSON data. 您的控制器无法理解您尝试解析JSON数据的类型。

The reason why you get LinkedHashMap is that Jackson uses it by default for "unknown" types. 之所以获得LinkedHashMap是因为Jackson默认将其用于“未知”类型。 Typical JSON data is actually a key-value map and Jackson preserves attributes ordering - that's why linked hash map is used. 典型的JSON数据实际上是键值映射,而Jackson保留属性排序-这就是使用链接的哈希映射的原因。

Which version of Jackson are you using? 您正在使用哪个版本的Jackson? I upgraded to 2.7.3 and when using generics (I have a base controller with common logic for saving, listing, etc) I had the same issue. 我升级到2.7.3,并且在使用泛型时(我具有具有保存,列出等通用逻辑的基本控制器)时遇到了相同的问题。 Rolling back to 2.6.5 allowed me to continue using my generic base class. 回滚到2.6.5允许我继续使用通用基类。 I haven't yet researched the reason for the issue but rolling back fixed it for me. 我尚未研究问题的原因,但回滚为我解决了该问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM