簡體   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