2015-11-03 60 views
2

我有一個問題,我有一個Web服務部署在Glassfish上,它不反序列化POST數據以正確添加一個人。Java REST服務JSON解析與單元測試解析不一致?

當我在測試用例中序列化/反序列化時,它工作正常。我如何讓GF像我的測試用例一樣使用ObjectMapper?我的bean受到了打擊,以及適用於我的測試用例的JSON,但在發佈到REST服務時不起作用。

public class PhoneNumber implements Serializable { 
    String countryCode; 
    String areaCode; 
    String subscriberNubmer; 
    String extension; 

    public PhoneNumber() { 
     super(); 
    } 

    /** 
    * @param countryCode 
    * @param areaCode 
    * @param subscriberNubmer 
    * @param extension 
    */ 
    public PhoneNumber(String countryCode, String areaCode, String subscriberNubmer, 
      String extension) { 
     super(); 
     this.countryCode = countryCode; 
     this.areaCode = areaCode; 
     this.subscriberNubmer = subscriberNubmer; 
     this.extension = extension; 
    } 
    ... getters and other stuff ... 
} 

@Entity 
@Table(name = "ent_person") 
public class Person implements Serializable, Comparable<Person> { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 
    /** 
    * Comment for <code>serialVersionUID</code> 
    */ 
    private static final long serialVersionUID = -4680156785318108346L; 

    protected String firstName; 

    protected String nickname; 

    protected String lastName; 

    @ElementCollection(fetch = FetchType.EAGER) 
    protected List<String> middleNames; 

    protected String idNum; 

    protected char isMale; 

    @Temporal(value = TemporalType.DATE) 
    protected Date birthday; 

    @ElementCollection(fetch = FetchType.EAGER) 
    @MapKeyColumn(name = "name") 
    @Column(name = "value") 
    protected Map<String, PhoneNumber> phoneNumbers; 

    public Person() { 
     super(); 
    } 

    /** 
    * @param firstName 
    * @param nickname 
    * @param lastName 
    * @param middleNames 
    * @param idNum 
    * @param isMale 
    * @param birthday 
    */ 
    public Person(String firstName, String nickname, String lastName, List<String> middleNames, 
      String idNum, char isMale, Date birthday, Map<String, PhoneNumber> phoneNumbers) { 
     super(); 
     this.firstName = firstName; 
     this.nickname = nickname; 
     this.lastName = lastName; 
     this.middleNames = middleNames; 
     this.idNum = idNum; 
     this.isMale = isMale; 
     this.birthday = birthday; 
     this.phoneNumbers = phoneNumbers; 
    } 
    ... getters and setters ... 
} 

這是通過測試案例序列化方法產生的JSON數據和在測試的情況下與所述ObjectMapper有正確解串。但是,它不會在Web應用程序中正確反序列化。

{ 
    "id": null, 
    "firstName": "John", 
    "nickname": "JJ", 
    "lastName": "Smith", 
    "middleNames": [ 
     "Stelling", 
     "Deering" 
    ], 
    "idNum": "js3234", 
    "isMale": "n", 
    "birthday": 778266673889, 
    "phoneNumbers": { 
     "Personal Mobile": { 
      "countryCode": "26", 
      "areaCode": "200", 
      "subscriberNubmer": "4069942", 
      "extension": null 
     }, 
     "Home": { 
      "countryCode": "79", 
      "areaCode": "115", 
      "subscriberNubmer": "9518863", 
      "extension": null 
     } 
    } 
} 

這裏是Web服務給我,當我發佈上述JSON。請注意,phoneNumbers地圖只有一個鍵「入口」,沒有值?

{"firstName":"John","id":1,"idNum":"js3234","isMale":"n","lastName":"Smith","middleNames":["Stelling","Deering"],"nickname":"JJ","phoneNumbers":{"entry":[]}} 

這是測試的情況下,偉大工程與上述JSON是這種情況下產生的內容(瓦爾字符串)

@Test 
public void testSimpleSerializeToFromJson() throws IOException { 
    int phoneNumberCount; 
    Person p; 

    p = BeanFactory.getDummyPerson(); 
    assertNotNull(p.getPhoneNumbers()); 
    phoneNumberCount = p.getPhoneNumbers().size(); 
    assertTrue(phoneNumberCount > 0); 

    String val = mapper.writeValueAsString(p); 
    assertNotNull(val); 


    Person p2 = mapper.readValue(val, Person.class); 
    System.out.println(p2.getPhoneNumbers()); 
    assertNotNull(p2.getPhoneNumbers()); 
    assertTrue(p2.getPhoneNumbers().size() == phoneNumberCount); 
    assertFalse(p == p2); 
    assertTrue(p2.equals(p)); 
} 

回答

1

好了,我終於找到了答案。根據this table

我不得不添加一個自定義MessageBodyReader讀取字符串的地圖不會自動反序列化。由於我已經有一個工作單元測試來讀取字符串,所以添加正確的類和註釋以及之後的所有工作都很簡單:

@Consumes("application/json") 
@Provider 
public class PersonReader 
implements MessageBodyReader<Person> { 
    ObjectMapper mapper; 

    public PersonReader(){ 
     mapper = new ObjectMapper(); 
    } 

    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 
     return type == Person.class; 
    } 

    public Person readFrom(Class<Person> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { 
     Person p = mapper.readValue(entityStream, Person.class); 
     return p; 
    } 
}