users@jersey.java.net

Required JSON format for JAXB beans

From: <shaper_at_sibmail.com>
Date: Mon, 19 Jan 2009 16:21:54 +0600 (NOVT)

Hi all,

1. We have modified json-from-jaxb sample from the
jersey-samples-1.0.1-project.zip as shown below (Apache Tomcat servlet
container is used for deployment):

@Provider
public final class JAXBContextResolver implements
ContextResolver<JAXBContext> {

    private final JAXBContext context;

    private final Set<Class<?>> types;

    private final Class<?>[] cTypes = {Flights.class, FlightType.class};

    public JAXBContextResolver() throws Exception {
        Map<String, Object> props = new HashMap<String, Object>();
        props.put(JSONJAXBContext.JSON_NOTATION,
JSONJAXBContext.JSONNotation.MAPPED);
        props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.TRUE);
        props.put(JSONJAXBContext.JSON_NON_STRINGS, new
HashSet<String>(1){{add("number");}});
        this.types = new HashSet<Class<?>>(Arrays.asList(cTypes));
        this.context = new JSONJAXBContext(cTypes, props);
    }

    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }

}

Output looks as follows (the number field value still as string in spite
of adding to non-strings):
{"flight":[{"flightId":"OK123","company":"Czech
Airlines","number":"123","aircraft":"B737"},
{"flightId":"OK124","company":"Czech
Airlines","number":"124","aircraft":"AB115"}]}

Could you clarify cause of the trouble?


2. Jettison user guide states (http://jettison.codehaus.org/User%27s+Guide):

Available since 1.1
When writing JSON documents, Jettison tries to convert objects to their
primitive representation and not to treat everything as a String. For
example the following snippet:
StringWriter strWriter = new StringWriter();
        Configuration config = new Configuration();
        MappedNamespaceConvention con = new
MappedNamespaceConvention(config);
        AbstractXMLStreamWriter w = new MappedXMLStreamWriter(con,
strWriter);

        w.writeStartElement("root");
        w.writeCharacters("true");
        w.writeEndElement();

        w.writeEndDocument();

        w.close();
        strWriter.close();

        System.out.println(strWriter.toString());
will print
{"root":true}
instead of
{"root":"true"}

This works fine for most use cases, but some users may want to have
control over this process. Jettison provides customizable type conversion
mechanism. Beside default type converter used, you can use SimpleConverter
which will treat everything as a String or write your own. For example,
StringWriter strWriter = new StringWriter();
        Configuration config = new Configuration();
        config.setTypeConverter(new SimpleConverter());
        MappedNamespaceConvention con = new
MappedNamespaceConvention(config);
        AbstractXMLStreamWriter w = new MappedXMLStreamWriter(con,
strWriter);

        w.writeStartElement("root");
        w.writeCharacters("true");
        w.writeEndElement();

        w.writeEndDocument();

        w.close();
        strWriter.close();

        System.out.println(strWriter.toString());
will produce
{"root":"true"}


Seems that Jersey calls props.put(JSONJAXBContext.JSON_NOTATION,
JSONJAXBContext.JSONNotation.MAPPED_JETTISON); uses
Jettison.SimpleConverter. But we need to have objects conversion to their
primitive representation as the default option, i.e. {"root":true}.

Could MAPPED_JETTISON be configured in Jersey to use default converter
instead of simple converter? If this option is not available, could you
extend it to use something like this?

props.put(JSONJAXBContext.JSON_NOTATION,
JSONJAXBContext.JSONNotation.MAPPED_JETTISON.DEFAULT_CONVERTER);


Thanks in advance.

Dmitry Sh.