josh.trow
josh.trow

Reputation: 4901

JAXB missing fields in list of elements

I've got an issue where for a hierarchy of classes that can contain each other and all extend a base class, one of them will not show details when added to a list of 'base' objects. I have to use JAXB because reasons, so I'm trying to track down what is missing or wrong. I've stripped it down to sample code below.

public class BaseSchema {}

@XmlRootElement(name="ObjectA")
@XmlAccessorType(XmlAccessType.FIELD)
public class ObjectA extends BaseSchema {
  private String thingA;
  @XmlElementWrapper(name="listOfBs")
  @XmlElement(name="b-item")
  private List<ObjectB> listB = new ArrayList<>();
  // getters and setters
}

@XmlAccessorType(XmlAccessType.FIELD)
public class ObjectB extends BaseSchema {
  private String thingB;
  @XmlElementWrapper(name="listOfCs")
  @XmlElement(name="c-item")
  private List<ObjectC> listC = new ArrayList<>();
  // getters and setters
}

@XmlAccessorType(XmlAccessType.FIELD)
public class ObjectC extends BaseSchema {
  private String thingC;
  @XmlElementWrapper(name="listOfBases")
  @XmlElement(name="base-item")
  private List<BaseSchema> listBase = new ArrayList<>();
  // getters and setters
}

@XmlAccessorType(XmlAccessType.FIELD)
public class ObjectD extends BaseSchema {
  private String thingD;
  // getter and setter
}

My root is always a known element type (ObjectA) so it is the only one with an XmlRootElement tag. Now for a sample dataset of an A holding a B holding a C holding some of each, this is the marshaled output (JAXB first, then XStream to show the data is there). You can see that JAXB is simply outputting a 'blank' element for the D item, with none of the internal fields - but all the rest work just fine.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ObjectA>
    <thingA>Base element</thingA>
    <listOfBs>
        <b-item>
            <thingB>B1</thingB>
            <listOfCs>
                <c-item>
                    <thingC>C1</thingC>
                    <listOfBases>
                        <base-item xsi:type="objectA" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                            <thingA>A1</thingA>
                            <listOfBs/>
                        </base-item>
                        <base-item/>
                        <base-item xsi:type="objectA" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                            <thingA>A2</thingA>
                            <listOfBs/>
                        </base-item>
                        <base-item xsi:type="objectB" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                            <thingB>B2</thingB>
                            <listOfCs/>
                        </base-item>
                        <base-item xsi:type="objectC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                            <thingC>C2</thingC>
                            <listOfBases/>
                        </base-item>
                        <base-item/>
                    </listOfBases>
                </c-item>
            </listOfCs>
        </b-item>
    </listOfBs>
</ObjectA>

===================
<test.schema.ObjectA>
  <thingA>Base element</thingA>
  <listB>
    <test.schema.ObjectB>
      <thingB>B1</thingB>
      <listC>
        <test.schema.ObjectC>
          <thingC>C1</thingC>
          <listBase>
            <test.schema.ObjectA>
              <thingA>A1</thingA>
              <listB/>
            </test.schema.ObjectA>
            <test.schema.ObjectD>
              <thingD>D1</thingD>
            </test.schema.ObjectD>
            <test.schema.ObjectA>
              <thingA>A2</thingA>
              <listB/>
            </test.schema.ObjectA>
            <test.schema.ObjectB>
              <thingB>B2</thingB>
              <listC/>
            </test.schema.ObjectB>
            <test.schema.ObjectC>
              <thingC>C2</thingC>
              <listBase/>
            </test.schema.ObjectC>
            <test.schema.ObjectD>
              <thingD>D2</thingD>
           </test.schema.ObjectD>
          </listBase>
        </test.schema.ObjectC>
      </listC>
    </test.schema.ObjectB>
  </listB>
</test.schema.ObjectA>
===================

Code to create the output:

public class MarshalTest {
  public void test() throws Exception {
    ObjectA base = new ObjectA();
    base.setThingA("Base element");

    ObjectB b1 = new ObjectB();
    b1.setThingB("B1");
    base.getListB().add(b1);

    ObjectC c1 = new ObjectC();
    c1.setThingC("C1");
    b1.getListC().add(c1);

    ObjectA a1 = new ObjectA();
    a1.setThingA("A1");
    c1.getListBase().add(a1);

    ObjectD d1 = new ObjectD();
    d1.setThingD("D1");
    c1.getListBase().add(d1);

    ObjectA a2 = new ObjectA();
    a2.setThingA("A2");
    c1.getListBase().add(a2);

    ObjectB b2 = new ObjectB();
    b2.setThingB("B2");
    c1.getListBase().add(b2);

    ObjectC c2 = new ObjectC();
    c2.setThingC("C2");
    c1.getListBase().add(c2);

    ObjectD d2 = new ObjectD();
    d2.setThingD("D2");
    c1.getListBase().add(d2);

    JAXBContext jaxbContext = JAXBContext.newInstance(base.getClass());
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    StringWriter writer = new StringWriter();

    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    jaxbMarshaller.marshal(base, writer);
    System.out.println(writer.toString());
  }

Upvotes: 1

Views: 506

Answers (1)

Halko Karr-Sajtarevic
Halko Karr-Sajtarevic

Reputation: 2268

I think the problem is that JAXB is not aware of your ObjectD class. Can you try to add @XmlSeeAlso({ ObjectA.class, ObjectB.class, ObjectC.class, ObjectD.class }) to your BaseSchema class? e.g.

@XmlSeeAlso({ ObjectA.class, ObjectB.class, ObjectC.class, ObjectD.class }
public class BaseSchema {}

Upvotes: 3

Related Questions