简体   繁体   English

Java REST 服务 JSON 解析与单元测试解析不一致?

[英]Java REST service JSON parsing inconsistent with unit test parsing?

I have a problem, I have a web service deployed on Glassfish and it is not de-serializing the POST data to add a person properly.我有一个问题,我在 Glassfish 上部署了一个 Web 服务,它没有反序列化 POST 数据以正确添加一个人。

When I serialize/de-serialize in a test case it works fine.当我在测试用例中序列化/反序列化时,它工作正常。 How do I make GF use an ObjectMapper like my test case?如何让 GF 像我的测试用例一样使用 ObjectMapper? My beans are blow, as well as the JSON that works with my test case but that does not work when posted to the REST service.我的 bean 以及与我的测试用例一起工作但在发布到 REST 服务时不起作用的 JSON。

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 ...
}

This is the JSON data generated by the test case serialization method and that de-serializes properly in the test case with the ObjectMapper there.这是由测试用例序列化方法生成的 JSON 数据,并且在带有ObjectMapper的测试用例中正确反序列化。 It does not, however, de-serialize properly in the web app.但是,它不会在 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
        }
    }
}

Here is what the web service gives me when I post the above JSON.这是当我发布上述 JSON 时 Web 服务给我的信息。 Note that the phoneNumbers map just has 1 key "entry" and no values???请注意,phoneNumbers 映射只有 1 个键“条目”而没有值???

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

This is the test case, works great and the JSON above is what this case generates (the val String)这是测试用例,效果很好,上面的 JSON 就是这个用例生成的(val 字符串)

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

OK, I finally found the answer.好的,我终于找到了答案。 The map would not automatically de-serialize according to this table地图不会根据 此表自动反序列化

I had to add a custom MessageBodyReader to read the String.我必须添加一个自定义 MessageBodyReader 来读取字符串。 Since I already had a working unit test to read the String, so it was a simple matter of adding the correct class and annotations and everything worked after that:因为我已经有一个工作单元测试来读取字符串,所以添加正确的类和注释很简单,之后一切正常:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM