Question

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?

Was it helpful?

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>

OTHER TIPS

You could do the following:

A

You can use the @XmlElementRef annotation on the aList field so that the element it uses comes from the @XmlRootElement annotation on the A class.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class A {

    private Long id;

    private String name;

    @XmlElementRef
    private List<A> aList;

}

Demo

Below is some sample code to prove that everything works.

import java.io.File;
import javax.xml.bind.*;

public class Demo {

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

        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.xml/Output

Below is the input to and output from running the demo code.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a>
    <id>1</id>
    <name>A</name>
    <a>
        <id>2</id>
        <name>B</name>
        <a>
            <id>3</id>
            <name>C</name>
        </a>
    </a>
</a>

XML Schema

Below is the XML schema that corresponds to this model. You could generate the model from it or start from the Java model.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="a" type="a"/>

  <xs:complexType name="a">
    <xs:sequence>
      <xs:element name="id" type="xs:long" minOccurs="0"/>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
      <xs:element ref="a" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top