users@jersey.java.net

JSON-JAXB unmarshalling null values as the String "null"

From: Chad McHenry <mchenryc_at_gmail.com>
Date: Wed, 20 May 2009 15:54:25 -0400

I'm POSTing in JSON, but my resource is unmarshalling values
explicitly set to null as the String "null".

According to the spec (http://json.org), sending null (NOT quoted)
should indicate the null value just the same as omitting the field.
Here though, fields omitted (i.e. "note") are properly unmarshalled as
null, but fields explicitly set to null (i.e. "firstName") are
unmarshalled as the String value "null".

Is there a setting I am missing in JAXBContextResolver?



==== POST to resource =============
$ > curl -X POST -D- -H 'Content-type: application/json' \
  -d '{"firstName":null,"lastName":"Smith"}' \
  --basic http://red:good@localhost/myapp/api/contact

HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Server: Jetty(6.1.16)

{"firstName":"null","id":14,"lastName":"Smith"}

==== Server log =============
INFO ContactResource - firstName: null len=4 (60)
INFO ContactResource - note: null len=0 (62)

==== ContactResource.java =============
@Path("/contact")
@Produces(MediaType.APPLICATION_JSON)
@Component
@Scope("singleton")
@Transactional
public class ContactResource {
    @POST
    public Contact create(Contact contact) {
        String name = contact.getFirstName();
        log.info("firstName: "+name+" len="+(name==null?0:name.length()));
        String note = contact.getNote();
        log.info("note: "+note+" len="+(note==null?0:note.length()));

        contactDao.insert(contact);

        return contact;
    }
}
==== JAXBContextResolver.java =============
@Provider
@Component
public final class JAXBContextResolver implements ContextResolver<JAXBContext> {
    private final JAXBContext context;
    private final Set<Class<?>> types;
    private final Class<?>[] cTypes = {
        Contact.class
    };
    public JAXBContextResolver() throws Exception {
        this.types = new HashSet<Class<?>>(Arrays.asList(cTypes));
        this.context = new
JSONJAXBContext(JSONConfiguration.natural().build(), cTypes);
    }
    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}
==== Contact.java =============
@XmlRootElement
public class Contact {
    private Integer id;
    private String firstName;
    private String lastName;
    private String note;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName == null ? null : firstName.trim();
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName == null ? null : lastName.trim();
    }
    public String getNote() {
        return note;
    }
    public void setNote(String note) {
        this.note = note == null ? null : note.trim();
    }
}