I'm trying to use JAXB to unmarshal a data (Polygon) with two @XmlJavaTypeAdapter annotations (Subscriber, Tag) to and from an XML file. Each object has it's own XML file, and the objects are related thus:
- Each Subscriber may hold multiple Polygons
- Each Polygon may hold multiple Subscribers
- Each Polygon may hold multiple Tags
I'm trying to unmarshall the Polygon XML file back to its class object, with its Subscribers and Tags in tact, but can't work out how to do it.
== Subscriber.java ==
@XmlRootElement(name = "Subscriber")
@XmlAccessorType(XmlAccessType.FIELD)
public class Subscriber {
private String ID;
private Set<Polygon> polygons;
@XmlAttribute(name = "ID")
public String getID() {
return this.ID;
}
public void setID(String ID) {
this.ID = ID;
}
@XmlJavaAdapter(PolygonXmlAdapter.class)
@XmlElementWrapper(name = "Polygons")
@XmlElement(name = "Polygon")
public set<Polygon> getPolygons() {
return this.polygons;
}
public void setPolygons(Set<Polygon> polygons) {
this.polygons = polygons;
}
}
== Polygon.java ==
@XmlRootElement(name = "{Polygon}")
@XmlAccessorType(XmlAccessType.FIELD)
public class Polygon {
private String ID;
private Set<Subscriber> subscribers;
private Set<Tag> tags
@XmlAttribute(name = "ID")
public String getID() {
return this.ID;
}
public void setID(String ID) {
this.ID = ID;
}
@XmlJavaAdapter(SubscriberXmlAdapter.class)
@XmlElementWrapper(name = "Subscribers")
@XmlElement(Subscriber)
public Set<Subscriber> getSubscribers() {
return this.subscribers;
}
@XmlJavaAdapter(TagXmlAdapter.class)
@XmlElementWrapper(name = "Tags")
@XmlElement(name = "Tag")
public Set<Tag> getTags() {
return this.tags
}
public void setTags(Set<Tag> tags) {
this.tags = tags;
}
}
== Tag.java ==
@XmlRootElement(name = "Tag")
@XmlAccessorType(XmlAccessType.FIELD)
public class Tag {
private String ID;
@XmlAttribute(name = "ID")
public String getID() {
return this.ID;
}
public void setID(String ID) {
this.ID = ID;
}
}
== SubscriberXmlAdapter.java ==
public class SubscriberXmlAdapter extends XmlAdapter<String, Subscriber> {
private Map<String, Subscriber> subscribers = new HashMap<>();
private Map<String, Subscriber> getSubscribers() {
return subscribers;
}
@Override
public Subscriber unmarshal(String v) throws Exception {
return subscribers.get(v);
}
@Override
public String marshal(Subscriber v) throws Exception {
return v.getID();
}
}
== TagXmlAdapter.java ==
public class TagXmlAdapter extends XmlAdapter<String, Tag> {
private Map<String, Tag> tags = new HashMap<>();
private Map<String, Tag> getTags() {
return tags;
}
@Override
public String unmarshal(String v) throws Exception {
return tags.get(v);
}
@Override
public String marshal(Tag v) throws Exception {
reutrn v.getID();
}
}
== SubscriberCollection.java ==
@XmlRootElement(name = "Subscribers")
@XmlAccessorType(XmlAccessType.FIELD)
public class SubscriberCollection {
private Collection<Subscriber> collection;
@XmlElement(name = "Subscriber")
public Collection<Subscriber> getSubscribers() {
return this.collection;
}
public void setCollection(Collection<Subscriber> collection) {
this.collection = collection;
}
}
== TagCollection.java ==
@XmlRootElement(name = "Tags")
@XmlAccessorType(XmlAccessType.FIELD)
public class TagCollection {
private Collection<Subscriber> collection;
@XmlElement(name="Tag")
public Collection<Tag> getSubscribers() {
return this.collection;
}
public void setCollection(Collection<Subscriber> collection) {
this.collection = collection;
}
}
And to execute the unmarshalling, three xml files - for subscribers, polygons, and tags - containing their respective data are used:
JAXBContext jaxbContext = JAXBContext.newInstance(SubscriberCollection.class, PolygonTagCollection.class, Polygon.class);
unmarshaller subUnmarshaller = jaxbContext.createunmarshaller();
SubscriberCollection subCollection = (SubscriberCollection) subUnmarshaller.unmarshal(new ByteArrayInputStream(subscribersXml.getBytes(StandardCharset.UTF_8.name())));
Unmarshaller tagUnmarshaller = jaxbContext.createUnmarshaller();
TagCollection tagCollectino = (TagCollection) tagUnmarshaller.un,arshal(new ByteArrayInputStream(tagXml.getBytes(StandardCharsets.UTF_8.name())));
Unmarshaller polUnmarshaller = jaxbContext.createUnmarshaller();
SubscriberXmlAdapter subAdapter = new SubscriberXmlAdapter();
for (Subscriber sub : subscriberCollection.getCollection()) {
subAdapter.getCollection().put(sub.getID(), sub);
}
TagXmlAdapter tagAdapter = new TagXmlAdapter();
for (Tag tag : tagCollection.getCollection()) {
tagAdapter.getCollection().put(tag.getID(), tag);
}
polUnmarshaller.setAdapter(SubscriberXmlAdapter.class subAdapter);
polUnmarshaller.unmarshal(new ByteArrayInputStream(polygonXml.getBytes(StandardCharsets.UTF_8.name())));
This unmarshalls the Polygon with the correct subscribers, but not with the correct tags.
I can only set one XmlAdapter to the unmarshaller, so it can only populate the subscribers or the tags within the polygon being unmarshalled.
Is there a way to combine these adapters? Or is there a better way of doing things altogether.
Thanks!