I am working with a colleague's API. The API returns a Response
with a list of objects or just one, singular object. The objects can be of multiple types. The return type is in XML. I am interested in parsing this XML via JAXB to get my classes, ideally in a flexible and generic way.
The following two XML responses are a sample of what I am speaking about.
Sample 1: A response with a list Jobs
containing Job
object.
<Response>
<Status>OK</Status>
<Jobs>
<Job>
<ID>J1</ID>
<Name>job name</Name>
</Job>
<Job>
<ID>J2</ID>
<Name>job name</Name>
</Job>
</Jobs>
</Response>
Sample 2: A response with one Job
.
<Response>
<Status>OK</Status>
<Job>
<ID>J123</ID>
<Name>job name</Name>
</Job>
</Response>
At the moment, I am constructing something as follows:
@XmlRootElement(name="Response")
@XmlAccessorType(XmlAccessType.FIELD)
public class Response {
@XmlElement(name = "Status")
protected Status status;
@XmlAnyElement(lax=true)
protected Object items;
}
Unmarshalling via
Response = (Response) unmarshaller.unmarshal(myXmlResponse);
But I'm receiving null
in my items when unmarshalling Sample 1
. Also, this approach gives me a bad feeling as I'm using Object
as a catch-all i.e. expecting both List<Job>
and Job
type. What am I doing wrong? Is there a better solution? Maybe my response class can have two generics, one for list of item
s and another for a single item
?
An approach in which the singular <Job>
is converted to a list of job
s with one element would also be interesting, but I'm not sure that can be a generic without modifying the XML response.
You could do this:
@XmlRootElement(name = "Response")
public class Response {
@XmlElement(name ="Status")
private Status status;
@XmlElements({
@XmlElement(name = "Job", type = Job.class),
@XmlElement(name = "Jobs", type = Jobs.class),
})
private List<?> jobs;
}
Then Job would be:
public class Job {
@XmlElement(name = "ID")
private String id;
@XmlElement(name = "Name")
private String name;
}
And Jobs:
public class Jobs {
@XmlElement(name = "Job")
private List<Job> jobs;
}
Update to answer on comment:
This is the cleanest way I could think of for handling these described payloads. The challenge is with the <Jobs></Jobs>
being there only some times.
There is a way to do it without embedded list but it is messier. I will copy it below so you can decide if you like it, or better to get another cleaner solution.
@XmlRootElement(name = "Response")
public class Response {
@XmlElement(name ="Status")
private Status status;
@XmlElement(name = "Job")
private List<Job> jobs;
@XmlElementWrapper(name = "Jobs")
@XmlElement(name = "Job")
private List<Job> jobsWrapped;
}