2015-06-15 19 views
5

Khi tôi muốn deserialize một thực thể với một thành viên đa hình, Jackson ném một com.fasterxml.jackson.databind.JsonMappingException, phàn nàn về một loại thông tin bị thiếu (... mà thực sự hiện diện trong JSON -> xem ví dụ) .Jackson so với mùa xuân HATEOAS so với đa hình

Unexpected token (END_OBJECT), expected FIELD_NAME: missing property '@class' that is to contain type id (for class demo.animal.Animal)\n at [Source: N/A; line: -1, column: -1] (through reference chain: demo.home.Home[\"pet\"])" 

Tất cả công việc thực tế được thực hiện bởi PagingAndSortingRepository từ Spring HATEOAS.

Tôi sử dụng khởi động mùa xuân V 1.2.4.RELEASE, có nghĩa là jackson là V 2.4.6 và Spring HATEOAS là V 0.16.0.RELEASE.

Ví dụ:

Tôi có một con vật cưng ở nhà:

@Entity 
public class Home { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int id; 

    @OneToOne(cascade = {CascadeType.ALL}) 
    private Animal pet; 

    public Animal getPet() { 
     return pet; 
    } 

    public void setPet(Animal pet) { 
     this.pet = pet; 
    } 

} 

Đó Pet là một số động vật - trong trường hợp này hoặc là một Cát hoặc một Dog. Nó loại được xác định bởi thuộc tính @class ...

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") 
public abstract class Animal { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int id; 

    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

} 

@Entity 
public class Cat extends Animal { 

} 

@Entity 
public class Dog extends Animal { 

} 

Tiếp theo là PagingAndSortingRepository này tiện dụng, cho phép tôi tiếp cận nhà của tôi qua REST/HATEOAS ...

@RepositoryRestResource(collectionResourceRel = "home", path = "home") 
public interface HomeRepository extends PagingAndSortingRepository<Home, Integer> { 

} 

Để xác nhận tất cả công cụ đó đang hoạt động, tôi có một thử nghiệm tại chỗ ...

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = DemoApplication.class) 
@WebAppConfiguration 
public class HomeIntegrationTest { 

    @Autowired 
    private WebApplicationContext ctx; 

    private MockMvc mockMvc; 

    @Before 
    public void setUp() { 
     this.mockMvc = webAppContextSetup(ctx).build(); 
    } 

    @Test 
    public void testRename() throws Exception { 

     // I create my home with some cat... 
     // http://de.wikipedia.org/wiki/Schweizerdeutsch#Wortschatz -> Büsi 
     MockHttpServletRequestBuilder post = post("/home/") 
       .content("{\"pet\": {\"@class\": \"demo.animal.Cat\", \"name\": \"Büsi\"}}"); 
     mockMvc.perform(post).andDo(print()).andExpect(status().isCreated()); 

     // Confirm that the POST request works nicely, so the JSON thingy is correct... 
     MockHttpServletRequestBuilder get1 = get("/home/").accept(MediaType.APPLICATION_JSON); 
     mockMvc.perform(get1).andDo(print()).andExpect(status().isOk()) 
       .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) 
       .andExpect(jsonPath("$._embedded.home", hasSize(1))) 
       .andExpect(jsonPath("$._embedded.home[0].pet.name", is("Büsi"))); 

     // Now the interesting part: let's give that poor kitty a proper name... 
     MockHttpServletRequestBuilder put = put("/home/1") 
       .content("{\"pet\": {\"@class\": \"demo.animal.Cat\", \"name\": \"Beauford\"}}"); 
     mockMvc.perform(put).andDo(print()).andExpect(status().isNoContent()); 
     // PUT will thow JsonMappingException exception about an missing "@class"... 

     MockHttpServletRequestBuilder get2 = get("/home/").accept(MediaType.APPLICATION_JSON); 
     mockMvc.perform(get2).andDo(print()).andExpect(status().isOk()) 
       .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) 
       .andExpect(jsonPath("$._embedded.home", hasSize(1))) 
       .andExpect(jsonPath("$._embedded.home[0].pet.name", is("Beaufort"))); 

    } 

} 

Thú vị tôi có thể tạo ngôi nhà của mình với mèo làm vật nuôi, nhưng khi tôi muốn cập nhật tên của con mèo, nó không thể deserialize J SON nữa ...

Bất kỳ đề xuất nào?

+0

Tại sao bạn cập nhật 'nhà riêng' khi bạn muốn thay đổi tên của động vật? 'Put' của bạn sẽ tạo ra một con vật mới. – zeroflagL

Trả lời

4

Tôi sẽ cố gắng trả lời một nửa.

Khi xử lý PUT (có thể là PATCH), spring-data-rest-webmvc hợp nhất dữ liệu JSON đã cho vào thực thể hiện tại. Trong khi làm như vậy, nó sẽ loại bỏ tất cả các thuộc tính không tồn tại trong thực thể từ cây JSON trước khi chuyển nó tới Jackson ObjectMapper. Nói cách khác, tài sản @class của bạn đã biến mất vào thời điểm Jackson nhận được deserialize đối tượng của bạn.

Bạn có thể làm việc này (để kiểm tra/trình diễn) bằng cách thêm thuộc tính @class làm tài sản thực tế cho thực thể của bạn (bạn phải đổi tên nó là classname). Bây giờ tất cả mọi thứ sẽ hoạt động tốt, tuy nhiên thực thể của bạn bây giờ có một tài sản classname vô dụng khác, mà có lẽ không phải là những gì bạn muốn.

Sử dụng cách tiếp cận @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.WRAPPER_OBJECT) cũng sẽ không hoạt động, vì lý do tương tự (ngoại trừ lần này toàn bộ đối tượng bao bọc được loại bỏ). Cũng như với cách tiếp cận ban đầu, GET và POST sẽ hoạt động tốt.

Toàn bộ nội dung trông giống như lỗi hoặc @JsonTypeInfo không được hỗ trợ trong tình huống spring-data-rest-webmvc.

Có thể ai đó khác có thể làm sáng tỏ thêm về điều này.

Các vấn đề liên quan