0
votes

I have a web service method like so. I map sending JSON via POST to the method and it is not setting the address field properly. I know the JSON is valid because it's straight out of a unit test that dumps a Person to JSON and reads it back. The test passes (the deserialized object has 2 phone numbers), and this is the exact string.

@POST
@Override
@Consumes({"application/xml", "application/json"})
public void create(Person entity) {
    System.out.println("Saving entity: " + entity);
    super.create(entity);
    System.out.println("Saved: " + entity);
}

When I post the JSON it does not set the phone numbers map on the object. Here is the output:

Info: Saving entity: Person{id=null, firstName=John, nickname=JJ, lastName=Smith, middleNames=[Stelling, Deering], idNum=js3234, isMale=n, birthday=null, phoneNumbers=null}

Info: Saved: Person{id=2, firstName=John, nickname=JJ, lastName=Smith, middleNames=[Stelling, Deering], idNum=js3234, isMale=n, birthday=null, phoneNumbers=null}

Here is the JSON:

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

The objects look like this:

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

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

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;
--- Snipped getters, setters, to string and constructors --

This is the PhoneNumber object

public class PhoneNumber implements Serializable {

private static final long serialVersionUID = -423634682785318106L;

public static transient final String HOME = "Home";

public static final String PERSONAL_MOBILE = "Personal Mobile";

public static final String OFFICE = "Office";

public static final String WORK_MOBILE = "Work Mobile";

public static final String FAX = "Fax";

public static final String PAGER = "Pager";

public static final String TOLL_FREE = "Toll Free";

public static final String OTHER = "Other";

String countryCode;

String areaCode;

String subscriberNubmer;

String extension;
1

1 Answers

0
votes

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