user4918214
user4918214

Reputation: 41

Unmarshal XML with dynamic root element using JAXB

I'm trying to integrate with a third-party system and depending on the type of object, the root element of the returned XML document changes. For example:

GET /objecttype1-1/ returns:
<?xml version="1.0" encoding="UTF-8"?>
<objecttype1 xmlns="path">
   <id>1</id>
   <description>obj1</description>
</objecttype1>

and:

GET /objecttype2-3 returns:
<?xml version="1.0" encoding="UTF-8"?>
<objecttype2 xmlns="path">
   <id>3</id>
   <address>home</address>
</objecttype2>

Since the sub-elements are not guaranteed to be the same (other than id), I figured a List with @XmlMixed @XmlAnyElement will take care of them. But how do I map the root elements? @XmlRootElement(name="???")

Due to technology limitations, I'm not able to use EclipseLink/MOXy. Thanks.

Upvotes: 4

Views: 756

Answers (1)

Alexander Nikolov
Alexander Nikolov

Reputation: 1979

Its been 5 years since this question was asked but I found working solution of the issue, sharing for the community.

First we define JAXB beans as follows:

@XmlRootElement(name = "objecttype1")
@XmlAccessorType(XmlAccessType.NONE)
public class Objecttype1 {

  @XmlElement(name = "id")
  private String id;

  @XmlElement(name = "description")
  private String description;

  public String getId() {
      return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }
}

@XmlRootElement(name = "objecttype2")
@XmlAccessorType(XmlAccessType.NONE)
public class Objecttype2 {

  @XmlElement(name = "id")
  private String id;

  @XmlElement(name = "address")
  private String address;

  public String getId() {
    return id;
   }

  public void setId(String id) {
    this.id = id;
  }

  public String getAddress() {
    return address;
  }

  public void setDescription(String address) {
    this.address = address;
  }
}

Next we need the JAXB context and the unmarshaller itself:

private static final JAXBContext jaxbContext;

 public Unmarshaller getUnmarshaller() {
    try {
        return jaxbContext.createUnmarshaller();
    } catch (JAXBException ex) {
        throw new IllegalStateException(ex);
    }
}

Having that, the JAXB context is loading its candidates and checks if there is a match amongs them by the root element name. We just unmarshal and check whats the type of received object:

try {
  Object unmarshalledObject = getUnmarshaller().unmarshal(new StringReader(xmlString));

  if (unmarshalledObject instanceof Objecttype1) {
   //do Objecttype1 related work
  } else if (unmarshalledObject instanceof Objecttype2) {
   //do Objecttype2 related work
  } else {
   // unexpected object type
  }
} catch (JAXBException ex) {
 //handle ex
}

Upvotes: 0

Related Questions