【问题标题】:JAXB 2.x: How to unmarshal an XML without knowing the target class?JAXB 2.x:如何在不知道目标类的情况下解组 XML?
【发布时间】:2011-07-27 15:53:03
【问题描述】:

如果有办法,如何做到这一点,我想知道最优雅的一种。 这是问题: - 假设你有一个抽象类 Z - 你有两个继承自 Z 的类:命名为 A 和 B。

您可以像这样编组任何实例(A 或 B):

JAXBContext context = JAXBContext.newInstance(Z.class);
Marshaller m = context.createMarshaller();
m.marshal(jaxbObject, ...an outputstream...);

在生成的 XML 中,您可以看到它是什么类型的实例(A 或 B)。

现在,你如何解组

JAXBContext jc = JAXBContext.newInstance(Z.class);
Unmarshaller u = jc.createUnmarshaller();
u.unmarshal(...an inputstream...)

我得到一个 UnmarshalException 说

"Exception Description: A descriptor with default root element {<my namespace>}<the root tag, e.g. A or B> was not found in the project]

javax.xml.bind.UnmarshalException"

那么,您如何进行解组以获得 Z 的实例,然后您可以在解组后进行测试,它是什么?例如z instanceof A 然后... z instanceof B 然后其他...等等。

感谢您提供任何想法或解决方案。

我使用 JRE1.6 和 MOXy 作为 JAXB Impl。

【问题讨论】:

    标签: java jaxb jaxb2 moxy


    【解决方案1】:

    那么您如何进行解组以便获得 Z 的实例,然后您可以测试 >解组后,它是什么?例如z instanceof A then... z instanceof B then >something else...etc.

    这应该可以工作...

    Unmarshaller u = jc.createUnmarshaller();
    Object ooo = u.unmarshal( xmlStream );
    if ( ooo instanceof A )
    {
        A myAclass = (A)ooo;
    }
    else if ( ooo instanceof B )
    {
        B myBclass = (B)ooo;
    }
    

    我自己测试过,效果很好。

    【讨论】:

    • 这很好,但还不够好。比方说,有一天你引入了 C 类,甚至可能是 D。有没有一种解决方案,你不必更新上面的代码部分?它应该自动与所有子类一起工作......
    【解决方案2】:

    我的问题没有解决方案!

    在任何情况下,您都必须准确地告诉解组器它应该解组到哪个对象。

    【讨论】:

    • 您关于解组器需要了解目标类型的断言是不正确的。在 Alex 的代码示例中,一旦解组器为 ooo 赋值,ooo 引用的对象就已经是目标类的实例。您如何选择转换该实例取决于您,因为符合条件的子类列表可能是无限的,其选择几乎可以肯定取决于业务定义的逻辑。
    【解决方案3】:

    有一个类似的问题here

    是否有可能通过提供 Person.class 来解组,并且解组器发现自己,是否必须解组到 ReceiverPerson.classSenderPerson.class

    @XmlRootElement(name="person")
    public class ReceiverPerson extends Person {
      // receiver specific code
    }
    
    @XmlRootElement(name="person")
    public class SenderPerson extends Person {
      // sender specific code (if any)
    }
    
    // note: no @XmlRootElement here
    public class Person {
      // data model + jaxb annotations here
    }
    

    【讨论】:

    • 显然,您总是必须提供解组器可以用作目标类的类列表,但这破坏了整个 OO 方法,您不需要提及所有可能的子类!
    【解决方案4】:

    每个XML Documents Must Have a Root Element,如果您想对两个实例使用相同的 UnMarshaller,您唯一的可能就是拥有一个共同的根元素,例如:

    <root>
      <A></A>
    </root>
    

    你的 xsd 文件看起来像这样

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
        <xs:annotation>
            <xs:documentation>
            example for stackoverflow
        </xs:documentation>
        </xs:annotation>
        <xs:element name="root" type="rootType"/>
        <xs:complexType name="rootType">
                <xs:choice>
                    <xs:element name="A" type="AType"/>
                    <xs:element name="B" type="BType"/>
                </xs:choice>
        </xs:complexType>
    
        ... your AType and BType definitions here
    
    </xs:schema>
    

    【讨论】:

    • 我刚试了下,不行。解组器不能解组它。它说:“这个类没有定义公共默认构造函数,或者构造函数引发了异常。”当然,抽象类 Z 不能被实例化。我期望的是解组检测 XML 中的实例类型信息并解组到正确的对象。
    • 有一个类似的问题,我现在正在测试这个答案:link
    • 这个答案不能解决问题。我也根本没有使用 XSD。只是普通的 POJO JAXB XML.
    猜你喜欢
    • 2016-06-17
    • 2011-11-03
    • 1970-01-01
    • 2010-10-21
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-14
    相关资源
    最近更新 更多