2016-02-10 371 views
2

我有一個spring rest web應用程序,它包含一個像下面這樣的通用休息控制器。傑森將對象序列化爲JSON時,GET方法正常工作。但是,當我嘗試調用save方法時,RequestBody參數正在轉換爲LinkedHashMap,而不是由T泛型定義的類型。Spring MVC Rest Controller @RequestBody解析

@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 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!

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

不良風格。控制器不應該是'@ Transactional'! – dit

+0

感謝您的諮詢! –

回答

1

您正在使用哪個版本的Jackson?我升級到2.7.3,當使用泛型(我有一個基本控制器與公共邏輯保存,列表等),我有同樣的問題。回滾到2.6.5允許我繼續使用我的泛型基類。我還沒有研究這個問題的原因,但回滾給我解決了。

+2

spring 4.3在出現時應該解決這個問題:完全支持Jackson 2.7的新類型分辨算法 – ctrlspace

2

我不認爲你可以達到你想要的。 Java泛型機制只在編譯時才起作用。編譯後,泛型類型被擦除並被實際類型替換(您的案例中的Object)。您的控制器無法理解您嘗試解析JSON數據的類型。

你爲什麼得到LinkedHashMap的原因是Jackson默認使用它爲「未知」類型。典型的JSON數據實際上是一個鍵值映射,Jackson保留屬性排序 - 這就是爲什麼使用鏈接哈希映射。

+0

這不完全正確。通用對象的實例被刪除(例如,您無法找到ArrayList 的實例的通用類型)。然而,如果你有一個擴展泛型類的類(我假設該帖子的作者正在做,因爲他的泛型類是抽象的),它在運行時就知道該類的泛型是什麼。這就是爲什麼類如Guava的[TypeToken](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/reflect/TypeToken.html)能夠確定有關泛型類型的信息一類。 –