Madz
Madz

Reputation: 1279

Jaxb will not capture all childnodes

I have an xml document which looks like this

<root>
<subElement>
    <a>an instance</a>
    <b>another instance</b>
    <problemElement>
      <option>1st instance</option>
      <option>2nd instance</option>
      <option>3rd instance</option>
    </problemElement>

</subElement>

<subElement>
    <a></a>
    <b></b>
    <problemElement>
      <option>instance</option>
    </problemElement>

</subElement>
</root>

and my jaxb classes look like this;

@XmlRootElement(name = "root")
@XmlType(name = "Root")
public class Root{

  @XmlElement(name = "subElement", required = true)
  private final List<SubElement> subElementList = new ArrayList<SubElement>();

  public List<SubElement> getSubElementList() {
    return subElementList;
  }
}



@XmlType(name = "SubElement", propOrder = {"a", "b", "problemElement"})
public abstract class SubElement{

  @XmlElement(required = true)
  private String a;

  @XmlElement(required = true)
  private String b;

  @XmlElement(name = "problemElement", required = true)
  private List<ProblemElement> problemElement= new ArrayList<ProblemElement>();

  public String getA() {
    return a;
  }

  public String getB() {
    return b;
  }

  public List<ProblemElement> getProblemElement() {
    return problemElement;
  }
}



@XmlType(name = "ProblemElement" )
public class ProblemElement {

  @XmlElement(required = true)
  private String option;


  public String getOption() {
    return option;
  }
}

Everything works fine except the problemElement. The list only returns the last option node value in the xml, in this case "3rd instance". What am I doing wrong?

Upvotes: 2

Views: 1454

Answers (2)

bdoughan
bdoughan

Reputation: 149047

SHORT ANSWER

For you use case I would leverage the @XmlElementWrapper annotation on the problemElement property:

@XmlElementWrapper(name="problemElement")
@XmlElement(name="option")
private List<ProblemElement> problemElement = new ArrayList<ProblemElement>();

The I would use the @XmlValue property on the option property:

  @XmlValue
  private String option;

LONG ANSWER

Below is a completely mapped example.

Root

package forum10531285;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "root")
@XmlType(name = "Root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlElement(name = "subElement", required = true)
    private final List<SubElement> subElementList = new ArrayList<SubElement>();

}

SubElement

package forum10531285;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlType(name = "SubElement", propOrder = { "a", "b", "problemElement" })
@XmlAccessorType(XmlAccessType.FIELD)
public class SubElement {

    @XmlElement(required = true)
    private String a;

    @XmlElement(required = true)
    private String b;

    @XmlElementWrapper(name="problemElement")
    @XmlElement(name="option")
    private List<ProblemElement> problemElement = new ArrayList<ProblemElement>();

}

ProblemElement

package forum10531285;

import javax.xml.bind.annotation.*;

@XmlType(name = "ProblemElement" )
@XmlAccessorType(XmlAccessType.FIELD)
public class ProblemElement {

  @XmlValue
  private String option;

}

Demo

package forum10531285;

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

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum10531285/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

input.xml/Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <subElement>
        <a>an instance</a>
        <b>another instance</b>
        <problemElement>
            <option>1st instance</option>
            <option>2nd instance</option>
            <option>3rd instance</option>
        </problemElement>
    </subElement>
    <subElement>
        <a></a>
        <b></b>
        <problemElement>
            <option>instance</option>
        </problemElement>
    </subElement>
</root>

Upvotes: 3

javatutorial
javatutorial

Reputation: 1944

Sorry but... your ProblemElement may have an indefinite number of options? If that's the case then you should code this instead of your ProblemElement class:

public class ProblemElement {
    private List<String> options;

    public List<String> getOptions() {
        return options;
    }
    // other stuff here
}

otherwise your JAXBinding will retrieve only the last option in the XML, in this case the 3rd. Of course you should rewrite your binding annotations accordingly.

Upvotes: 2

Related Questions