Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to force jettison to write an array, even if there is only one element in the array?

With the simplified example below:

I get the following, as expected:

{"person":{"name":"john","tags":["tag1","tag2"]}}

However, if I only set one tag, I get this:

{"person":{"name":"john","tags":"tag1"}}

And I was expecting to get this:

{"person":{"name":"john","tags":["tag1"]}}

That is, jettison has removed the array for tags, because there is only one element in the array.

I think this is pretty unsafe.

How to force jettison to write an array, even if there is only one element?

Note: I am aware that there are other alternatives to jettison, such as StAXON. However, here I am asking how to achieve this using Jettison. Please do not suggest another alternative to jettison.

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.*;

import java.io.*;
import javax.xml.bind.*;
import javax.xml.stream.XMLStreamWriter;
import org.codehaus.jettison.mapped.*;


public class JettisonTest {
    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Person.class);

        Person person = new Person();
        person.name = "john";
        person.tags.add("tag1");
        person.tags.add("tag2");

        Configuration config = new Configuration();
        MappedNamespaceConvention con = new MappedNamespaceConvention(config);
        Writer writer = new OutputStreamWriter(System.out);
        XMLStreamWriter xmlStreamWriter = new MappedXMLStreamWriter(con, writer);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.marshal(person, xmlStreamWriter);
    }
}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
class Person {
    String name;
    List<String> tags = new ArrayList<String>();
}
like image 798
David Portabella Avatar asked Sep 13 '25 14:09

David Portabella


1 Answers

I found this: https://blogs.oracle.com/japod/entry/missing_brackets_at_json_one

It seems that adding a line to your context resolver to explicitly state that tags is an array is the way to do this; i.e.

props.put(JSONJAXBContext.JSON_ARRAYS, "[\\"tags\\"]");

NB: I'm not familiar with Jettison, so have no personal experience to back this up; only the info on the above blog post.

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {

    private JAXBContext context;
    private Class[] types = {ArrayWrapper.class};

    public JAXBContextResolver() throws Exception {
        Map props = new HashMap<String, Object>();
        props.put(JSONJAXBContext.JSON_NOTATION, "MAPPED");
        props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.TRUE);

        props.put(JSONJAXBContext.JSON_ARRAYS, "[\\"tags\\"]"); //STATE WHICH ELEMENT IS AN ARRAY

        this.context = new JSONJAXBContext(types, props);
    }

    public JAXBContext getContext(Class<?> objectType) {
        return (types[0].equals(objectType)) ? context : null;
    }

}
like image 167
JohnLBevan Avatar answered Sep 15 '25 14:09

JohnLBevan