Search code examples
javajsonjakarta-eejaxbjettison

Marshalling the Java objects (without @XmlRootElement) to JSON via Jettison


I have done the marshalling of an JAXB object (Which contains @XmlRootElement) to JSON using Jettison. But I can not convert a simple java object which has no annotations like @XmlRootElement to JSON. I would like to know "Is it mandatory to have that @XmlRootElement to marshall an object to JSON?"

I am getting the following Exception when I try to marshall the java object to Json

com.sun.istack.SAXException2: unable to marshal type "simpleDetail" as an element because it is missing an @XmlRootElement annotation

What could be the issue?


Solution

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

    The JAXB (JSR-222) specification does not cover JSON-binding. Instead of using a JAXB implementation with the Jettison library, you could use EclipseLink JAXB (MOXy) that offers native JSON-binding. Below is an example.

    JAVA MODEL

    Foo

    import java.util.List;
    import javax.xml.bind.annotation.*;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Foo {
    
        private List<Bar> mylist;
    
    }
    

    Bar

    import javax.xml.bind.annotation.*;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Bar {
    
        private int id;
        private String name;
    
    }
    

    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: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):

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

    DEMO CODE

    Demo

    MOXy does not require the @XmlRootElement annotation, and you can use the JSON_INCLUDE_ROOT property to tell MOXy to ignore the presence of any @XmlRootElement annotations. When the root element is ignored you need to use an unmarshal method that takes a class parameter to specify the type you are unmarshalling.

    import java.util.*;
    import javax.xml.bind.*;
    import javax.xml.transform.stream.StreamSource;
    import org.eclipse.persistence.jaxb.JAXBContextProperties;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            Map<String, Object> properties = new HashMap<String, Object>(2);
            properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
            properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
            JAXBContext jc = JAXBContext.newInstance(new Class[] {Foo.class}, properties);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            StreamSource json = new StreamSource("src/forum15404528/input.json");
            Foo foo = unmarshaller.unmarshal(json, Foo.class).getValue();
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(foo, System.out);
        }
    
    }
    

    input.json/Output

    We see that no root element is present in the input or output.

    {
       "mylist" : [ {
          "id" : 104,
          "name" : "Only one found"
       } ]
    }
    

    ADDITIONAL INFORMATION