当前位置: 首页 > 知识库问答 >
问题:

JAXB 将 XML 解封为抽象类型的错误子类

徐嘉谊
2023-03-14

我有一个抽象类A,有两个子类B和C。A看起来像这样:

@XmlTransient
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "A", propOrder = {
    "operation",
    "origin",
})
@XmlSeeAlso({B.class, C.class})
public abstract class A {

    @XmlElement(required = true)
    protected Operation operation;

    @XmlElement(required = true)
    protected Origin origin;

    // getters and setters
}

乙:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "A") // root element is A for all subclasses
@XmlType(name = "B", propOrder = {
    "operation",
    "origin",
    "b",
})
public class B extends A {

    @XmlElement(required = true)
    protected String b;

    // getter and setter
}

C:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "A") // root element is A for all subclasses.
@XmlType(name = "C", propOrder = {
    "operation",
    "origin",
    "c",
})
public class C extends A {

    @XmlElement(required = true)
    protected String c;

    // getter and setter
}

如何创建 JAXB 上下文:

private static JAXBContext createJaxbContext() throws JAXBException {
    if(jaxbContext == null) {
        final ClassLoader classLoader = A.class.getClassLoader();
        final String contextPath = A.class.getPackage().getName();
        jaxbContext = JAXBContext.newInstance(contextPath, classLoader);
    }
    return jaxbContext;
}

当我传入符合抽象类A但具有属性B的XML时,我希望JAXB能够将其解组为B类型的对象(如果属性C存在,C也是如此)。目前发生的情况是,它试图将所有XML字符串解组到C语言,并且只解组到C语言,这导致了一个ClassCastException。

我尝试在根节点上将子类指定为类型——例如:

<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="C">
    <operation id="123" action="insert"/>
    <origin>
        <environment>DEV</environment>
        <instance>root</instance>
    </origin>
    <c>c value</c>
</A>

但这并不能解决问题。

我做错了什么?会感谢任何帮助:)

编辑:如果有帮助,这是用于解组的方法

public static A toA(String xml) throws Exception{
    try {
      final Unmarshaller jaxbUnmarshaller = getJaxbContext().createUnmarshaller();
      final StringReader reader = new StringReader(xml);
      return (A) jaxbUnmarshaller.unmarshal(reader);
    } catch (JAXBException e) {
      throw new Exception("Failed to unmarshal A " + "[" + e.toString() + "].");
    }
  }

这是我的ObjectFactory:

@XmlRegistry
public class ObjectFactory {

    private final static QName A_QNAME = new QName("", "A");

    public ObjectFactory() {}

    public B createB() {
        return new B();
    }

    public C createC() {
        return new C();
    }

    public Operation createOperation() {
        return new Operation();
    }

    public Origin createOrigin() {
        return new Origin();
    }

    public A createA(A value) {
        return new JAXBElement<>(A_QNAME, A.class, null, value).getValue();
    }
}

共有1个答案

孔经武
2023-03-14

我有一个解决方案,但它使用组合而不是继承。我不确定你是否有理由延长课程。

我简化了类A,因此我不必为源代码和操作创建类,但我相信您明白了这一点(如果没有,请告诉我):

@XmlAccessorType(XmlAccessType.FIELD)
public class A {

    // operation and origin stay the same

    @XmlElements({
            @XmlElement(name = "b", type = B.class),
            @XmlElement(name = "c", type = C.class),
    })
    protected Object bOrC;
}

类 B 和 C 将如下所示:

@XmlAccessorType(XmlAccessType.FIELD)
public class B {

    @XmlValue
    private String value;
}

你可以有一个B和C都可以扩展的接口,而不是A类中的Object。

然后它会因为有

<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <!--<operation id="123" action="insert"/>-->
    <!--<origin>-->
        <!--<environment>DEV</environment>-->
        <!--<instance>root</instance>-->
    <!--</origin>-->
    <c>c value</c>
</A>

 类似资料:
  • 是否有任何JAXB绑定可以告诉JAXB代码生成器将Java类生成为,而不必在XSD中将相应的XML类型标记为? 情况如下: > 我在xsd中定义架构: 我使用内联JAXB绑定(“inline”==“直接在模式中”)来指示应该生成JAXB类的包(): 我使用内联JAXB绑定为我的每个复杂类型(在本例中、和)指示实现类的名称: 我从模式生成JAXB类。这导致: 我自己编写类: 使用这两个类层次结构这样

  • 我对JAXB很陌生,在解封一般对象时遇到了麻烦。问题是我需要能够封送和解封任何对象(java.lang.object)。我成功地进行了封送处理,但是当我运行解封处理时,响应中得到的是一个“ElementNSimpl”对象,而不是我自己的对象。 这是涉及的bean: message.java somebean.java jaxb.index的内容: 生成的xml很好()但是在解封后计算“msg.ge

  • 问题内容: 我正在尝试使用JAXB解组一些XML,但出现“无法创建…的实例”异常。我知道为什么- 它试图建立一个抽象类的实例。我想要的是让它成为特定实现类的实例。我的目标是对setter方法进行特定于类的检查。对于BarImpl,也许“ qux”是有效的baz值,但BarImpl2想要做其他事情。 我没有通过注释Foo来实现这一目标,但是如果我不注释bar,事情就会变得很丑。 问题答案: 您可以执

  • 我目前正在尝试将一些现有的XML解组到我手工创建的几个类中。问题是,我总是得到一个错误,告诉我,JaxB需要一个天气元素,但却找到了一个天气元素。(?) UnMarshalException:意外元素(URI:“http://www.aws.com/aws”,本地:“weather”)。需要的元素为<{}API>、<{}Location>、<{}Weather> 这就是我试图解析的XML: 我不太

  • 我使用JAXB将一些xml解组到一个对象中。 我有一个从抽象类继承的类。我已经将抽象类标记为@XmlTransient。然后使用XMLType PropOrder,我可以访问抽象类中的属性,如下所示: 凉。问题是有时它不是我想访问的元素,而是一个属性。通常,您将使用@XMLAttribute来定义此类属性,以指示值存储在 xml 特性而不是元素中。但是,鉴于我已经在定义了“id”的抽象类上使用了

  • 好啊我是JAXB新手,我对XmlID和XmlIDREF有一些问题,其中ID位于抽象类中。 我的问题是: 此类包含一个抽象实体,在本例中是一个字符串。 此类包含两个列表,一个列表包含“SomeClass”的实例,另一个列表包含“EntityImpl”的实例 impl被添加到res,res和impl都被添加到根目录上各自的列表中。 我想要的结果是引用SomeClass实体中impl的Id,但结果是: