I am developing some classes that are going to be serialized in an XML format (which does not have an XSD available to auto-generate code from), and have been trying to work with Jackson to handle the XML part. There are a few different output formats, which have some boilerplate attributes shared among them at the root level. I would like to avoid duplicating code in all my classes to represent those common properties. Moving the common properties to a superclass and using inheritance would be one way to get this to work, but that seems wrong from a OO perspective. What I would really like to do is define some additional class that contains the shared properties, and then have an instance of that class as a field in each of the "real" classes, and then use some kind of XML unwrapping on that field, so the shared items appear on the enclosing object.
A co-worker far more familiar with Jackson than I am suggested that I tag that field with @JsonUnwrapped, but I have been having some unexpected results. Before diving down into the example below, are there are any known/expected limitations on how XML would get unwrapped using this annotation? Examples: If I need something like the target output: <Root xmlns="urn:parentNS" xmlns:childNS="urn:childNS" ParentAttribute="parentAttrValue" childNS:ChildAttribute="childAttrValue"> <ParentElement>parentElemValue</ParentElement> </Root> Where Root is one of the output document types I need, with ChildAttribute being an item that also needs to appear in other output document types, I create a class Child.java as ======================= Child.java ======================= package test; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; public class Child { @JacksonXmlProperty(namespace = "urn:childNS", localName = "ChildAttribute", isAttribute = true) private String childAttribute = null; public String getChildAttribute() { return childAttribute; } public void setChildAttribute(String childAttribute) { this.childAttribute = childAttribute; } } ======================= And then create Root.java as ======================= Root.java ======================= package test; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; @JacksonXmlRootElement(namespace = "urn:parentNS", localName = "Root") public class Root { @JacksonXmlProperty(namespace = "urn:parentNS", localName = "ParentAttribute", isAttribute = true) private String parentAttribute = null; @JacksonXmlProperty(namespace = "urn:parentNS", localName = "ParentElement") private String parentElement = null; @JsonUnwrapped private Child child = null; public String getParentAttribute() { return parentAttribute; } public void setParentAttribute(String parentAttribute) { this.parentAttribute = parentAttribute; } public String getParentElement() { return parentElement; } public void setParentElement(String parentElement) { this.parentElement = parentElement; } public Child getChild() { return child; } public void setChild(Child child) { this.child = child; } } ======================= Using a simple main to test it out: ======================= Main.java ======================= package test; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class Main { public static void main(String[] args ) { Root rc = new Root(); rc.setParentAttribute("parentAttrValue"); rc.setParentElement("parentElemValue"); Child cc = new Child(); cc.setChildAttribute("childAttrValue"); XmlMapper mapper = new XmlMapper(); try { String xml = mapper.writeValueAsString(rc); System.out.println(xml); } catch (JsonProcessingException e) { e.printStackTrace(); } } } ======================= results in XML output for which the ParentElement element is serialized as an *attribute *on the Root element, even though it's not marked with isAttribute = true. Why is ParentElement getting handled like this? <Root xmlns="urn:parentNS" xmlns:childNS="urn:childNS" ParentAttribute="parentAttrValue" childNS:ChildAttribute="childAttrValue" ParentElement="parentElemValue /> My coworker later suggested also adding @JacksonXmlProperty(isAttribute = true) to the shared property, which *seems *to fix the problem. That is, updating Root.java with ======================= Root.java ======================= ... @JsonUnwrapped @JacksonXmlProperty(isAttribute = true) private Child child = null; ... ======================= results in <Root xmlns="urn:parentNS" xmlns:childNS="urn:childNS" ParentAttribute="parentAttrValue" childNS:ChildAttribute="childAttrValue"> <ParentElement>parentElemValue</ParentElement> </Root> Except something else is now happening under the hood, because if I were to, say, add an element to the Child class, as ======================= Child.java ======================= package test; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; public class Child { ... @JacksonXmlProperty(namespace = "urn:childNS", localName = "ChildElement") private String childElement = null; ... public String getChildElement() { return childElement; } public void setChildElement(String childElement) { this.childElement = childElement; } } ======================= and modify Main.java ======================= Main.java ======================= ... cc.setChildElement("childElemValue"); ... ======================= now ChildElement gets serialized as an attribute, even as ParentElement is still handled correctly. <Root xmlns="urn:parentNS" xmlns:childNS="urn:childNS" ParentAttribute="parentAttrValue" childNS:ChildAttribute="childAttrValue" childNS:ChildElement="childElemValue"> <ParentElement>parentElemValue</ParentElement> </Root> I won't add more sample code here, but if I change the ChildAttribute property to also be an element, things work as expected again, with the two properties of Child appearing as two subelements to Root. So it seems like using an additional class this way only works if the shared properties are all attributes (and the JacksonXmlProperty annotation is used in conjunction with JsonUnwrapped), or the shared properties are all elements (in which case JsonUnwrapped alone gets the job done). Is all that behavior expected, or am I outside the realm of what Jackson is meant to do for XML? -- You received this message because you are subscribed to the Google Groups "jackson-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user+unsubscr...@googlegroups.com. To post to this group, send email to jackson-user@googlegroups.com. For more options, visit https://groups.google.com/d/optout.