Disclaimer: This is just a very simple example. My scenario is much more complex than this.
Scenario:
My input XML:
<root>
...
<element>
Hello <name type="first">John</name>. Your policy number <policy number=1234/> has arrived.
Please contact <contact brand="XPTO">999-9999</contact> for more information.
</element>
...
</root>
My models: Root.java
@XmlRootElement(name = "root")
public class Root {
@XmlElement
protected Element element;
... (many other elements)
//gets and sets
}
Element.java
@XmlRootElement(name = "element")
public class Element {
@XmlElementRefs({
@XmlElementRef(name = "name", type = Name.class, required = false),
@XmlElementRef(name = "policy", type = Policy.class, required = false),
@XmlElementRef(name = "contact", type = Contact.class, required = false),
})
@XmlJavaTypeAdapter(CommonElementAdapter.class)
protected List<CommonElement> content;
@XmlAnyElement
@XmlMixed
protected List<String> value;
//gets and sets
}
Name/Policy/Contact.class (All of them has the very similar style)
@XmlRootElement(name = "name")
public class Name extends CommonElement {
@XmlValue
protected String value;
@XmlAttribute
protected String type;
//gets and sets
@Override
public CommonElement unmarshal(CommonElement content) {
//Do some stuff here with content. E.g.:
content.setValue(content.getValue().toUpperCase());
return content;
}
}
CommonElement.java
@XmlTransient
public abstract class CommonElement {
public CommonElement unmarshal (CommonElement value) {
return value;
}
}
CommonElementAdapter.java
public class CommonElementAdapter extends XmlAdapter<CommonElement, CommonElement> {
@Override
public CommonElement unmarshal(CommonElement content) throws Exception {
return content.unmarshal(content); //Call the unmarshal for each element
}
@Override
public CommonElement marshal(CommonElement content) throws Exception {
return content;
}
}
Expected result:
<root>
...
<element>
Hello <name type="first">JOHN</name>. Your policy number <policy number=1234/> has arrived.
Please contact <contact brand="XPTO">999-9999</contact> for more information.
</element>
...
</root>
Requirements:
- The final text must be exactly as in the input XML, keeping the order as received.
- The elements inside the tag must have it's on adapter. As my solution, it's inside the element itself, being called by CommonElementAdapter.
- I CAN'T use MOXy or any other custom implementation.
My issue:
This way I put here, I can make all the text and elements appear in the result, but the order isn't correct. I'm getting something like this:
<element>
<name type="first">JOHN</name>
<policy number=1234/>
<contact brand="XPTO">999-9999</contact>
Hello . Your policy number has arrived.
Please contact for more information.
</element>
I can change this removing the List<String>
value from Element.java and changing the List<CommonElement>
to List<Object>
, so the value would be included at the content
variable, keeping the order. But, this way, I couldn't make the Adapter work.