2015-06-15 9 views
5

जब मैं एक पॉलिमॉर्फ सदस्य के साथ एक इकाई को deserialize करना चाहता हूं, जैक्सन com.fasterxml.jackson.databind.JsonMappingException फेंकता है, एक लापता प्रकार की जानकारी के बारे में शिकायत (... जो वास्तव में JSON में मौजूद है -> उदाहरण देखें) ।जैक्सन बनाम स्प्रिंग हैटोज़ बनाम पॉलिमॉर्फिज्म

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\"])" 

सभी वास्तविक कार्य स्प्रिंग हैटोज़ से एक पेजिंग एंड सोर्सिंग रिपोजिटरी द्वारा किया जाता है।

मैं वसंत-बूट वी 1.2.4.RELEASE का उपयोग करता हूं, जिसका अर्थ है कि जैक्सन वी 2.4.6 है और स्प्रिंग हैटॉस वी 0.16.0.RELEASE है।

उदाहरण:

मैं घर पर एक पालतू जानवर है:

@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; 
    } 

} 

पालतू पशु कुछ है - इस मामले में या तो एक बिल्ली या एक कुत्ता में। यह है प्रकार ... @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 { 

} 

तो फिर वहाँ इस आसान PagingAndSortingRepository, जो मुझे बाकी/HATEOAS के माध्यम से अपने घर तक पहुँचने के लिए अनुमति देता है ...

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

} 

सभी पुष्टि करने के लिए है कि सामान काम कर रहा है, मैं जगह में एक परीक्षण है ...

@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"))); 

    } 

} 

दिलचस्प बात यह है कि मैं एक पालतू जानवर के रूप बिल्ली के साथ मेरे घर बना सकते हैं, लेकिन जब मैं बिल्ली यह जम्मू deserialize नहीं कर सकते हैं की नाम को अपडेट करना बेटा अब और ...

कोई सुझाव?

+0

जब आप जानवर के नाम को बदलना चाहते हैं तो आप 'होम' क्यों अपडेट करते हैं? आपका 'put' एक नया जानवर बनायेगा। – zeroflagL

उत्तर

4

मैं आधे उत्तर का प्रयास करने जा रहा हूं।

एक पुट (शायद पैच भी) को संसाधित करते समय, spring-data-rest-webmvc दिए गए JSON डेटा को मौजूदा इकाई में विलीन करता है। ऐसा करने पर, यह उन सभी गुणों को स्ट्रिप्स करता है जो JSON पेड़ से से पहले जैक्सन ObjectMapper पर जाने से पहले इकाई में मौजूद नहीं हैं। दूसरे शब्दों में, आपके @class संपत्ति जैक्सन द्वारा आपके ऑब्जेक्ट को deserialize करने के समय से चला गया है।

आप अपनी @class संपत्ति को अपनी इकाई के लिए वास्तविक संपत्ति के रूप में जोड़कर (परीक्षण/प्रदर्शन उद्देश्यों के लिए) इस पर काम कर सकते हैं (आपको इसे निश्चित रूप से नाम देना होगा, classname कहें)। अब सबकुछ ठीक काम करेगा, हालांकि आपकी इकाई में अब अन्यथा बेकार classname संपत्ति है, जो शायद आप नहीं चाहते हैं।

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.WRAPPER_OBJECT) दृष्टिकोण का उपयोग भी इसी तरह के कारण के लिए काम नहीं करेगा (इस समय को छोड़कर पूरे रैपर ऑब्जेक्ट को हटा दिया जाता है)। साथ ही मूल दृष्टिकोण के साथ, जीईटी और पोस्ट ठीक काम करेंगे।

पूरी बात एक बग या @JsonTypeInfo की तरह दिखती है spring-data-rest-webmvc स्थिति में समर्थित नहीं है।

शायद कोई और इस पर कुछ और प्रकाश डाल सकता है।

संबंधित मुद्दे