关于java:Spring MVC Rest Controller @RequestBody Parsing

Spring MVC Rest Controller @RequestBody Parsing

我有一个SpringRestWeb应用程序,它包含一个通用的REST控制器,如下所示。让Jackson将对象序列化为JSON,get方法工作得很好。但是,当我尝试调用save方法时,RequestBody参数将被转换为LinkedHashMap,而不是T泛型类型定义的类型。

1
2
3
4
5
6
7
8
9
10
11
@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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  "id":null,
  "version":null,
  "name":"Copel",
  "disabled":false,
  "type":"P",
  "labels":[
      {
        "id":null,
        "version":null,
        "name":"unidade consumidora"
      }
   ]
}

我得到以下错误:

HTTP Status 500 - Request processing failed; 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!

弹簧配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@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,"/*");
    }
}

我的代码有什么问题?


我认为你不能实现你想要的。Java泛型机制仅在编译时起作用。编译后,泛型类型将被删除并替换为实际类型(在您的情况下为Object)。您的控制器无法理解您试图解析JSON数据的类型。

之所以得到LinkedHashMap,是因为默认情况下杰克逊将其用于"未知"类型。典型的JSON数据实际上是一个键值映射,而Jackson保留了属性排序——这就是使用链接哈希映射的原因。


你用的是哪个版本的杰克逊?我升级到2.7.3,当使用泛型(我有一个基本控制器,具有用于保存、列出等的公共逻辑)时,我遇到了同样的问题。回滚到2.6.5允许我继续使用泛型基类。我还没有研究出这个问题的原因,但回头帮我解决了。