Search code examples
javajsonjerseyglassfishmoxy

Getting Glassfish's MOXy to convert JSON to POJO


I have a web application that uploads files through a MULTIPART_FORM_DATA POST which has both binary data and JSON Strings in it. (The JSON strings are created with the browser's JSON.stringify(obj) function).

According to the documentation Glassfish since 4.0.1 uses MOXy for unmarshalling JSON and XML objects.

My method looks like this:

@POST
@Path("put")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response put(@FormDataParam("file") List<FormDataBodyPart> bodyParts,
                    @FormDataParam("metadata") List<String> metaParts) throws JAXBException {

    JAXBContext jbc = JAXBContext.newInstance(MetaData.class);

    for (int index = 0; index < metaParts.size(); index += 1) {

        MetaData meta = null;
        String metaString = metaParts.get(index);
        if (metaString != null && !metaString.isEmpty()) {
            Unmarshaller um = jbc.createUnmarshaller();
            // um.setProperty(???, "application/json");
            meta = (MetaData) um.unmarshal(new StreamSource(new StringReader(metaString)));
        }

The code like this will attempt to parse the data in metaString as an XML document so it throws an exception.

Searching through the available documentation I find that the solution for this for the EclipseLink MOXy implementation appears to be to do a

um.setProperty("eclipselink.media-type", "application/json");

That doesn't work because the Glassfish 5 implementation of MOXy is from com.sun.xml.* not Eclipse. Tracing the code it seems that this implementation will throw an Exception on any setProperty call since it doesn't support any implementation specific properties.

Yet I know Sun's MOXy can do it because it is processing my HTTP requests/responses just fine. Yet I can find no examples or documentation anywhere -- all roads lead to the EclipseLink implementation.

Does anyone know how to do this?


Solution

  • You don't need to manually parse the data. What you can do is get the body part as a FormDataBodyPart as you have already done for the "file" part. From the FormDataBodyPart, you would then need to set the media type to application/json1, then just get the POJO using bodyPart.getValueAs(POJO.class).

    public Response put(@FormDataBodyPart("metadata") FormDataBodyPart metaDataPart) {
        metaDataPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
        MetaData metaData = metaDataPart.getValueAs(MetaData.class);
    }
    

    See more about this in File upload along with other object in Jersey restful web service


    1 - In a multipart request, each body part has it's own Content-Type header. If you don't set it, it will automatically be considered text/plain as the default. With Javascript, you have no way to set the content-type of individual parts, so it will default to text/plain. But we need it to be application/json so that the JAX-RS JSON provider is used for the deserialization.