2

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.

When I serialize/de-serialize in a test case it works fine. How do I make GF use an ObjectMapper like my test case? 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.

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. It does not, however, de-serialize properly in the web app.

{
    "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. Note that the phoneNumbers map just has 1 key "entry" and no values???

{"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)

@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 Answer 1

1

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. 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;
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.