我有一个抽象类 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
}
B :
@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();
}
}
答案 0 :(得分:0)
我有一个解决方案,但是它使用组合而不是继承。我不确定您是否有必要扩展该类。
我简化了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。
然后将其解编为具有<c>
或<b>
值就可以了:
<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>