5

I'm trying to unmarshall input JSON into JAXB objects with Eclipselink. However, when I try to do this, I find that nested objects end up being set as null. I can try and unmarshall the nested object by itself, and it will work up until the point that it has to unmarshall a further nested object, which is also then set to null.

For example, take this class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "event", propOrder = {
"objectBs"
})
public class ObjectA
implements Serializable
{

    private final static long serialVersionUID = 56347348765454329L;
    @XmlElement(required = true)
    protected ObjectA.ObjectBs objectBs;

    public ObjectA.ObjectBs getObjectBs() {
        return objectBs;
    }

    public void setObjectBs(ObjectA.ObjectBs value) {
        this.objectBs = value;
    }

    public boolean isSetObjectBs() {
        return (this.objectBs!= null);
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "objectB"
    })
    public static class ObjectBs
        implements Serializable
    {

        private final static long serialVersionUID = 56347348765454329L;
        @XmlElement(required = true)
        protected List<ObjectB> objectB;

        public List<ObjectB> getObjectB() {
            if (objectB == null) {
                objectB = new ArrayList<ObjectB>();
            }
            return this.objectB;
        }

        public boolean isSetObjectB() {
            return ((this.objectB!= null)&&(!this.objectB.isEmpty()));
        }

        public void unsetObjectB() {
            this.objectB = null;
        }

    }
}

Where ObjectA has an object called ObjectBs which contains a list of ObjectB. When I try unmarshalling this class, any other field that ObjectA has would be correctly filled, and the ObjectBs object would be created, but the list of ObjectB would be empty. But, if I unmarshall just one ObjectB by itself, it will be created with it's fields filled, up until it's own nested objects.

This is the code I'm using to unmarshall the JSON:

JAXBContext jc = JAXBContextFactory.createContext(
    "com.package1"
    + ":com.package2"
    + ":com.package3"
    , null);
Unmarshaller um = jc.createUnmarshaller();
um.setProperty("eclipselink.media-type", "application/json"); 
um.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
ObjectA objA = unmarshaller.unmarshal(new StreamSource(
    new StringReader(json)), ObjectA.class).getValue();

And some example JSON:

        {
                "objectBs": [
                    {
                        "a": "blahblah",
                        "b": 123456,
                        "c": "abc blah 123 blah",
                        "nestedObject": {
                            "evenMoreNestedObjects": {
                                "d": "blah",
                                "e": "blahblahblah",
                                "anotherNestedObject": {
                                    "x": 25,
                                    "y": 50
                                }
                        }}}]
        }
  • Similar: https://stackoverflow.com/questions/16365788/unmarshalling-nested-objects-from-json – Vadzim May 20 '19 at 21:15

1 Answers1

6

You didn't provide the JSON you are trying to unmarshal, but I've done a little reverse engineering and below is an example that works using the model you posted in your question:

import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
        unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
        StreamSource json = new StreamSource("src/forum17866155/input.json");
        ObjectA objectA = unmarshaller.unmarshal(json, ObjectA.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
        marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(objectA, System.out);
    }

}

input.json/Output

{
   "objectBs" : {
      "objectB" : [ {
      }, {
      } ]
   }
}
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • Thanks for your quick reply. I tried your method of using JAXBContext.newInstance() but now I get: javax.xml.bind.PropertyException: name: eclipselink.media-type value: application/json. Also, I added some example JSON. – Prashan Dharmasena Jul 25 '13 at 19:28
  • @PrashanDharmasena - When creating the `JAXBContext` on classes the `jaxb.properties` file needs to be in the same package as one of the class the `JAXBContext` is created on. The classes in your question do not match the objects in your question is it possible for you to fix that? Also you can take a look at what the JSON output is and compare that to what you are trying to input. – bdoughan Jul 25 '13 at 19:41
  • 1
    Thanks for your help, it turns out that it my input JSON wasn't matching up to the classes. – Prashan Dharmasena Jul 26 '13 at 12:57