ARTICLE AD BOX
I'm trying to marshal a Root object to XML using JAXB (the built‑in implementation in JDK 8u472). To control the output structure I wrote an XmlAdapter that adapts Root into a nested MiddleRoot class.
Simplified code
@XmlJavaTypeAdapter(RootAdapter.class) public class Root { private String a, b, c, d, e; // getters/setters... } public class RootAdapter extends XmlAdapter<MiddleRoot, Root> { // marshal: Root -> MiddleRoot // unmarshal: MiddleRoot -> Root } @XmlRootElement(name = "root") public class MiddleRoot{ @XmlElement(name = "head") private Head head; @XmlElement(name = "body") private Body body; static class Head{ private String a,b,c; // getter and setter } static class Body{ private String d,e; // getter and setter } // getter and setter }Marshalling code
JAXBContext context = JAXBContext.newInstance(Root.class, MiddleRoot.class); Marshaller marshaller = context.createMarshaller(); marshaller.marshal(root, System.out);ERROR
javax.xml.bind.MarshalException - with linked exception: [com.sun.istack.internal.SAXException2: class "com.ff.Root" nor any of its super class is known to this context or lacks a @XmlRootElement]What I found by debugging
Tracing the JAXB source code (com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl) shows:
My questions
Is my usage of @XmlJavaTypeAdapter on the root class correct, or does the root class always need @XmlRootElement? If I must add @XmlRootElement to Root, will the adapter still be invoked?Desired output
<root> <head> <a>a</a> <b>b</b> <c>c</c> </head> <body> <d>d</d> <e>e</e> </body> </root>Additional debugging details
1. Exception thrown in com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot because tagName is null. 2. tagName is assigned in the ClassBeanInfoImpl constructor via ci.isElement(), which checks whether RuntimeClassInfo.elementName is null. 3. elementName is determined in ModelBuilder.getClassInfo ClassInfoImpl.parseElementName: it returns null if the class has no @XmlRootElement.