Search code examples
xmljsonjaxbjettison

XML wrapped list to JSON array via Jettison and JAXB


I'm using JAXB to marshal an annotated object to XML in the form:

  <channels>
     <channel>Test A</channel>
     <channel>Test B</channel>
  </channels>

I want to marshal this to JSON instead using JAXB (ala http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html) but it marshals to something like the following:

  "channels" : {
    "channel" : [ "Test A", "Test B" ]
  },

Really I want it to marshal into the following form:

  "channels" : {
    {"Test A"}, {"Test B"}
  },

How can I do this? Is it the right thing to do?


Solution

  • Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

    Below is how you could support this use case using the JSON-binding in EclipseLink JAXB (MOXy).

    Java Model (Root)

    Below is the Java model that I will use for this example.

    import java.util.*;
    import javax.xml.bind.annotation.*;
    
    @XmlRootElement
    public class Root {
    
        private List<String> channels = new ArrayList<String>();
    
        @XmlElementWrapper
        @XmlElement(name="channel")
        public List<String> getChannels() {
            return channels;
        }
    
    }
    

    Specify MOXy as the JAXB Provider (jaxb.properties)

    To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: ):

    javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
    

    Demo Code

    In the demo code below we will output the same instance to both XML and JSON.

    import javax.xml.bind.*;
    import org.eclipse.persistence.jaxb.MarshallerProperties;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Root.class);
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    
            Root root = new Root();
            root.getChannels().add("Test A");
            root.getChannels().add("Test B");
    
            // Output XML
            marshaller.marshal(root, System.out);
    
            // Output JSON
            marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
            marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
            marshaller.setProperty(MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
            marshaller.marshal(root, System.out);
        }
    
    }
    

    Output

    Below is the output from running the demo code:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <channels>
          <channel>Test A</channel>
          <channel>Test B</channel>
       </channels>
    </root>
    
    {
       "channels" : [ "Test A", "Test B" ]
    }
    

    For More Information