簡體   English   中英

JAXB unmarshaller.unmarshal 何時返回 JAXBElement<MySchemaObject> 還是一個 MySchemaObject?

[英]when does JAXB unmarshaller.unmarshal returns a JAXBElement<MySchemaObject> or a MySchemaObject?

我有兩個代碼,在兩個不同的 java 項目中,做幾乎相同的事情,(根據 xsd 文件解組 web 服務的輸入)。

但在一種情況下,我應該這樣寫:(輸入是占位符名稱)(元素是 OMElement 輸入)

ClassLoader clInput = input.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("input", clInput);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() );

在另一個庫中,我必須使用 JAXBElement.getValue(),因為它是一個返回的 JAXBElement,而一個簡單的 (Input) 轉換只會崩潰:

Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() ).getValue();

你知道是什么導致了這種差異嗎?

如果根元素唯一對應於 Java 類,則將返回該類的實例,否則將返回JAXBElement

如果您想確保始終獲得域對象的實例,您可以利用JAXBInstrospector 下面是一個例子。

演示

package forum10243679;

import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    private static final String XML = "<root/>";

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBIntrospector jaxbIntrospector = jc.createJAXBIntrospector();

        Object object = unmarshaller.unmarshal(new StringReader(XML));
        System.out.println(object.getClass());
        System.out.println(jaxbIntrospector.getValue(object).getClass());

        Object jaxbElement = unmarshaller.unmarshal(new StreamSource(new StringReader(XML)), Root.class);
        System.out.println(jaxbElement.getClass());
        System.out.println(jaxbIntrospector.getValue(jaxbElement).getClass());
    }

}

輸出

class forum10243679.Root
class forum10243679.Root
class javax.xml.bind.JAXBElement
class forum10243679.Root

這取決於根元素的類上是否存在XmlRootElement 注釋

如果從 XSD 生成 JAXB 類,則應用以下規則:

  • 如果根元素的類型是匿名類型 -> 生成的類中添加 XmlRootElement 注解
  • 如果根元素的類型是頂級類型 -> 從生成的類中省略 XmlRootElement 注釋

出於這個原因,我經常為根元素選擇匿名類型。

您可以使用自定義文件自定義此匿名類型的類名。 例如創建一個 bindings.xjc 文件,如下所示:

<jxb:bindings version="1.0"
              xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
              xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jxb:bindings schemaLocation="yourXsd.xsd" node="/xs:schema">
        <jxb:bindings  node="//xs:element[@name='yourRootElement']">
            <jxb:class name="YourRootElementType"/>
        </jxb:bindings> 
    </jxb:bindings>
</jxb:bindings>

您需要將正確的@XMLRootElement添加到 JAXB 生成的類中 - 它應該具有命名空間:

@XmlRootElement(namespace="http://your.namespace.com/", name="yourRootElement")

看看相關的問題(有很多很好的技巧): Class Cast Exception when try to unmarshall xml?

感謝您的所有解釋和鏈接,我寫這篇文章是為了處理這兩種情況,使用 Annotation Introspection。

這樣做的好處是:

  • 不修改生成的java類
  • 允許所有可能的 xsd 格式

它適用於輸出和輸入,據我所知更通用:

public class JaxbWrapper {

    private static boolean isXmlRootElement(Class classT){
        
        Annotation[] annotations = classT.getAnnotations();
        
        for(Annotation annotation : annotations){
            if(annotation instanceof XmlRootElement){
                return true;
            }
        }       
        
        return false;
    }
    
    public static Object unmarshall(Class classObjectFactory, Class classObject, XMLStreamReader xmlStreamReader){
        
        Package pack = classObjectFactory.getPackage();
        String strPackageName = pack.getName();
        
        Object returnObject = null;
        
        try {
            JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());
            
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            
            returnObject = unmarshaller.unmarshal( xmlStreamReader );
            
            boolean bIsRootedElement = isXmlRootElement(classObject);
            if(!bIsRootedElement)
            {
                JAXBElement jaxbElement = (JAXBElement) returnObject;
                returnObject = jaxbElement.getValue();              
            }
        }
        catch (JAXBException e) {
            /*...*/
        }   

        return returnObject;
    }
    
    private static void writeToXml(Class classObjectFactory, Object obj, XMLStreamWriter xmlStreamWriter){
        
        Package pack = classObjectFactory.getPackage();
        String strPackageName = pack.getName();
        
        try {       
            JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());
            Marshaller marshaller = jc.createMarshaller();
            marshaller.marshal(obj, xmlStreamWriter);
        }
        catch(JAXBException e) {
            /*...*/
        }       
    }
    
    public static String marshall(Class classObjectFactory, Class classObject, Object obj){
        
        Object objectToMarshall = obj; 
        
        boolean bIsRootedElement = isXmlRootElement(classObject);
        if(!bIsRootedElement)
        {
            Package pack = classObjectFactory.getPackage();
            String strPackageName = pack.getName();
            
            String strClassName = classObject.getName();
            
            QName qName = new QName(strPackageName, strClassName);
            
            JAXBElement jaxbElement = new JAXBElement(qName, classObject, null, obj);
            
            objectToMarshall = jaxbElement; 
        }
        
        StringWriter sw = new StringWriter();
        XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
        XMLStreamWriter xmlStreamWriter = null;
        
        try {
            xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(sw);
            
            writeToXml(classObjectFactory, objectToMarshall, xmlStreamWriter);

            xmlStreamWriter.flush();
            xmlStreamWriter.close();
        } 
        catch (XMLStreamException e) {
            /*...*/
        }

        return sw.toString();
    }
}

我也有同樣的問題。 JAXB unmarshaller.unmarshal 返回JAXBElement<MyObject>而不是所需的MyObject

我找到並刪除了@XmlElementDecl 問題已經解決了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM