Avoiding code duplication using JAXB with container-like elements with a similar structure

Situation

I use the MOXy JAXB implementation to work with a large XML document whose schema has many similar complex types. In particular, there are about two dozen types that act as elements of a list shell with the following structure:

<ITEMS attr1="X" attr2="Y"> <ITEM>...</ITEM> ... <EXTENSION/> <ITEMS> 

For each of these items, similar to list-wrapper, the name changes and the list item contains changes. However, attributes (which are all optional) and a single EXTENSION element (also optional) are always present. Here is an example of using two types:

 <ROLES visible="false"> <ROLE type="X"/> <ROLE type="Y"/> </ROLES> <PAYMENTS visible="true"> <PAYMENT> <PAYEENAME>Joe</PAYEENAME> </PAYMENT> <EXTENSION> <SOMETHING>Here</SOMETHING> </EXTENSION> </PAYMENTS> 

Question

I would like to avoid code duplication, because the only thing that changes between these elements is the name and one or more elements that it contains. What is the best way to do this?

I can only see two possible solutions.

one

Create a specific class using generics to indicate the type of object that will be used in a changing collection. Then using MOXy's external OX mappings to indicate how any individual class usage should be serialized. Something like:

 public class GenericContainer<T> { @XmlAttribute protected Boolean visibile; @XmlElement(name = "Extension") protected Extension extension; // OX Mappings done in external meta file protected List<T> items; ... } 

While I like this option, it is not possible to override the OX class mappings for each use.

2

Creating a base class without the List property, and then creating one specific class for each custom wrapper element. This solution definitely works, but in the end I will have about two dozen almost identical classes.

Is there one option or is there a better way to handle this that I haven't thought about?

Thanks in advance!

+8
java design xml jaxb
source share
1 answer
 public class GenericContainer { private Boolean visible; private Object extension; private List<Object> nodes; @XmlAttribute public Boolean isVisible() { return visible; } public void setVisible(Boolean visible) { this.visible = visible; } @XmlElement(name="EXTENSION") public Object getExtension() { return extension; } public void setExtension(Object extension) { this.extension = extension; } @XmlAnyElement public List<Object> getNodes() { return nodes; } public void setNodes(List<Object> nodes) { this.nodes = nodes; } } 

And to read the XML instance

  JAXBContext jaxbContext = JAXBContext.newInstance("jaxbtest1"); Unmarshaller um = jaxbContext.createUnmarshaller(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new File("src/test1.xml")); Node node = doc.getFirstChild(); JAXBElement<GenericContainer> jaxbE = um.unmarshal(node, GenericContainer.class); GenericContainer gc = jaxbE.getValue(); Boolean vis = gc.isVisible(); Element ext = (Element)gc.getExtension(); for(Object o : gc.getNodes()) { Element listItem = (Element)o; } 

But is code duplication really important? If your schema has a common extension base for list container types and you use xjc, why avoid separate classes? After all, the JAXB idea has a class of values ​​for each unique complex type.

If you can create general-purpose logic that processes similar but different types of XML and does not want a large number of Java classes, you can switch to StAX.

0
source share

All Articles