Search code examples
xsdjaxb2maven-jaxb2-plugin

JAXB - marshalling with recursive dependency


is anybody try to marshal JAXB object with recurisive referency? I have following class:

public class A {

   private Long id;
   private String name;
   private List<A> aList;

}

and I'd like to marshall it to:

<a>
  <a>
    <a>...</a>
  ...
  </a>
...
</a>

I'm using maven plugin to auto generate JAXB class from XSD. Any suggestions?


Solution

  • Below is how you can support this use case starting from your XML schema.

    XML SCHEMA (schema.xsd)

    The following XML schema is based on the comment you made to a previous answer (http://stackoverflow.com/a/14317461/383861).

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.example.org" 
        xmlns:tns="http://www.example.org"
        elementFormDefault="qualified">
    
        <xs:element name="b">
            <xs:complexType>
                <xs:sequence>
                    <xs:element ref="tns:a" maxOccurs="unbounded" />
                </xs:sequence>
            </xs:complexType>
        </xs:element>
        <xs:element name="a">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="id" type="xs:long" />
                    <xs:sequence>
                        <xs:element ref="tns:a" minOccurs="0" maxOccurs="10" />
                    </xs:sequence>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    
    </xs:schema>
    

    GENERATED MODEL

    The following code was generated using the xjc tool. The get/set methods and comments have been removed to save space.

    A

    package org.example;
    
    import java.util.List;
    import javax.xml.bind.annotation.*;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "id",
        "a"
    })
    @XmlRootElement(name = "a")
    public class A {
    
        protected long id;
        protected List<A> a;
    
    }
    

    B

    package org.example;
    
    import java.util.List;
    import javax.xml.bind.annotation.*;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "a"
    })
    @XmlRootElement(name = "b")
    public class B {
    
        @XmlElement(required = true)
        protected List<A> a;
    
    }
    

    package-info

    @javax.xml.bind.annotation.XmlSchema(
            namespace = "http://www.example.org", 
            elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
    package org.example;
    

    ObjectFactory

    package org.example;
    
    import javax.xml.bind.annotation.XmlRegistry;
    
    @XmlRegistry
    public class ObjectFactory {
    
        public ObjectFactory() {
        }
    
        public B createB() {
            return new B();
        }
    
        public A createA() {
            return new A();
        }
    
    }
    

    DEMO CODE

    import java.io.File;
    import javax.xml.bind.*;
    import org.example.A;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance("org.example");
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            File xml = new File("src/forum14306965/input.xml");
            A a = (A) unmarshaller.unmarshal(xml);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(a, System.out);
        }
    
    }
    

    INPUT (input.xml)/OUTPUT

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <a xmlns="http://www.example.org">
        <id>1</id>
        <a>
            <id>2</id>
            <a>
                <id>3</id>
            </a>
        </a>
    </a>