繁体   English   中英

为什么在Jaxb2Marshaller中需要检查根元素?

[英]Why check for root element is required in Jaxb2Marshaller?

我正在使用Jaxb2Marshaller通过spring @ResponseBody注释来编组Java bean。 对于JSON编组工作正常。 但对于xml,我不断得到HTTP 406响应。 Jaxb2Marshaller类中的一点点挖掘显示它为有界类检查@XmlRootElement(参见下面的代码片段)。

从xsd生成java代码时,我的pojo不包含@XmlRootElement,并且AnnotationMethodHandlerAdapter未识别正确的消息转换器,最终导致406。

我没有从xsd自动生成java代码,而是创建了自己的pojo类并使用了@XmlRootElement。 然后编组工作正常。

我想理解为什么让@XmlRootElement检查有界类很重要。 或者在xsd中将元素指定为@XmlRootElement的任何方法。

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;
}

编辑:Blaise的回答帮我解决了@XmlRootElement问题。 但是,如果有人有任何关于为什么需要检查XmlRootElement的信息,那将是一个很好的信息。

检查@XmlRootElement注释的原因

在将对象编组为XML时,Spring需要一个根元素。 JAXB提供了两种机制来执行此操作:

  1. @XmlRootElement注释
  2. 将根对象包装在JAXBElement的实例中。

由于对象未包装在JAXBElement中,因此Spring确保满足其他条件。

如何生成@XmlRootElement

JAXB将为XML模式中的所有全局元素生成@XmlRootElement注释。 以下将导致@XmlElement:

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

@XmlRootElement未生成时

不会为全局类型生成@XmlRootElement注释。

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

而是以@XmlElementDecl注释的形式在ObjectFactory类(使用@XmlRegistry注释)中捕获与全局类型相关联的全局元素。 这些注释

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);
    }

}

@XmlElementDecl注释提供与@XmlRootElement类似的信息,可用于解组操作。 JAX-RS实现可能不会利用@XmlElementDecl,但是由于编组操作需要将对象包装在JAXBElement对象中以提供根元素名称/命名空间。

这是一个众所周知的问题: https//jira.springsource.org/browse/SPR-7931

“在Jaxb2Marshaller中检查@XmlRootElement注释应该是可选的”

您可以将JaxbElement用于没有@XmlRootElement批注的类。 如果要从xsd生成代码,则@XmlRootElement注释仅放置在未引用的顶级对象上

Edit

See @Blaise Doughan answer.

@XmlRootElement will be placed only if there is no reference to that type in another type.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM