@XmlJavaTypeAdapter(RootAdapter.class)
public class Root {
private String a, b, c, d, e;
// getters/setters...
}
public class RootAdapter extends XmlAdapter {
// 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
}
Код маршаллинга
JAXBContext context = JAXBContext.newInstance(Root.class, MiddleRoot.class);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(root, System.out);
ОШИБКА
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]
Что я обнаружил при отладке
Отслеживание исходного кода JAXB (com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl) показывает:
- Root не имеет аннотации @XmlRootElement, поэтому его elementName становится нулевым.
- Во время создания JAXBContext ClassInfoImpl.parseElementName возвращает значение null, а позднее tagName имеет значение null при вызове сериализацииRoot.
- Обработка @XmlJavaTypeAdapter, похоже, не предоставляет имя корневого элемента.
Мои вопросы
- Правильно ли я использую @XmlJavaTypeAdapter в корневом классе, или корневому классу всегда нужен @XmlRootElement?
- Если мне нужно добавить @XmlRootElement в Root, будет ли адаптер по-прежнему вызываться?
Желаемый результат
a
b
c
d
e
Дополнительные сведения об отладке
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.