30

2 つの異なる Java プロジェクトで、ほぼ同じことを行う 2 つのコードがあります (xsd ファイルに従って Web サービスの入力をアンマーシャリングします)。

しかし、あるケースでは、次のように書く必要があります: (Input はプレースホルダー名です) ( element は OMElement 入力 )

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

もう 1 つのライブラリでは、JAXBElement.getValue() を使用する必要があります。これは、返されるのは JAXBElement であり、単純な (入力) キャストは単純にクラッシュするためです。

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

何がこのような違いにつながるか知っていますか?

4

5 に答える 5

31

ルート要素が Java クラスに一意に対応する場合は、そのクラスのインスタンスが返され、そうでない場合は aJAXBElementが返されます。

常にドメイン オブジェクトのインスタンスを取得したい場合は、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
于 2012-04-20T20:42:26.217 に答える
4

これは、ルート要素のクラスに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>
于 2012-04-20T10:01:15.250 に答える
1

すべての説明とリンクのおかげで、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();
    }
}
于 2012-04-20T15:45:05.853 に答える
1

適切な JAXB 生成クラスに追加する必要が@XMLRootElementあります。名前空間が必要です。

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

関連する質問を見てください (良いヒントがたくさんあります): Class Cast Exception when try to unmarshall xml?

于 2012-04-20T09:56:45.147 に答える