Why is root element verification required in Jaxb2Marshaller?

I am using Jaxb2Marshaller to marshal Java beans through the spring @ResponseBody annotation. For JSON, marshaling worked fine. But for xml, I constantly got an HTTP 406 response. A little digging into the Jaxb2Marshaller class shows that it checks @XmlRootElement for restricted classes (see snippet below).

When generating java code from xsd, my pojo does not contain @XmlRootElement, and the proper message converter was not identified by AnnotationMethodHandlerAdapter and finally the result is 406.

Instead of automatically generating java code from xsd, I created my own pojo class and used @XmlRootElement. Then marshaling works fine.

I want to understand why it is important to have @XmlRootElement validation for restricted classes. Or any way to specify an element as @XmlRootElement in xsd.

Code snippet from Jaxb2Marshaller:

public boolean supports(Class clazz) { return supportsInternal(clazz, true); } private boolean supportsInternal(Class<?> clazz, boolean checkForXmlRootElement) { if (checkForXmlRootElement && clazz.getAnnotation(XmlRootElement.class) == null) { return false; } if (clazz.getAnnotation(XmlType.class) == null) { return false; } if (StringUtils.hasLength(getContextPath())) { String className = ClassUtils.getQualifiedName(clazz); int lastDotIndex = className.lastIndexOf('.'); if (lastDotIndex == -1) { return false; } String packageName = className.substring(0, lastDotIndex); String[] contextPaths = StringUtils.tokenizeToStringArray(getContextPath(), ":"); for (String contextPath : contextPaths) { if (contextPath.equals(packageName)) { return true; } } return false; } else if (!ObjectUtils.isEmpty(classesToBeBound)) { return Arrays.asList(classesToBeBound).contains(clazz); } return false; } 

Edit: Blay's answer helped me solve the @XmlRootElement problem. But if someone has information on why the XmlRootElement check is required, there will be good information.

+4
source share
3 answers

Why is the @XmlRootElement annotation marked for

Spring requires a root element when sorting an object in XML. JAXB provides two mechanisms for this:

  • @XmlRootElement annotations
  • Wrap around the root object in a JAXBElement instance.

Because the object is not wrapped in a JAXBElement, Spring provides another condition.

How to create an @XmlRootElement element

JAXB will generate the @XmlRootElement annotation for all global elements in the XML schema. The following will result in @XmlElement:

 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="foo"> <xsd:complexType> ... </xsd:complextType> </xsd:element> </xsd:schema> 

When @XmlRootElement is not generated

@XmlRootElement annotations will not be generated for global types.

 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="foo" type="foo"/> <xsd:complexType name="foo"> ... </xsd:complexType> </xsd:schema> 

Instead, the global element (s) associated with the global types is captured in the ObjectFactory class (annotated with @XmlRegistry) as @XmlElementDecl annotations. These annotations

 package generated; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlElementDecl; import javax.xml.bind.annotation.XmlRegistry; import javax.xml.namespace.QName; @XmlRegistry public class ObjectFactory { private final static QName _Foo_QNAME = new QName("", "foo"); public Foo createFoo() { return new Foo(); } @XmlElementDecl(namespace = "", name = "foo") public JAXBElement<Foo> createFoo(Foo value) { return new JAXBElement<Foo>(_Foo_QNAME, Foo.class, null, value); } } 

The @XmlElementDecl annotation provides similar information as @XmlRootElement and can be used for operations without a marshal. JAX-RS implementations probably don't use @XmlElementDecl, however, since marshal operations require the object to be wrapped in a JAXBElement object to provide a root name / namespace.

+5
source

this is a known issue: https://jira.springsource.org/browse/SPR-7931

"Checking the @XmlRootElement annotation should be made optional in Jaxb2Marshaller"

+2
source

You can use JaxbElement for classes that do not have @XmlRootElement annotation. @XmlRootElement annotations are only placed in top level objects without a link if you generate your code from xsd

 Edit See @Blaise Doughan answer. @XmlRootElement will be placed only if there is no reference to that type in another type. 
+1
source

Source: https://habr.com/ru/post/1337118/


All Articles