我一直在阅读关于这个主题的所有问题,但没有一个与我的问题有关。我有这些类(每个类都在自己的文件中):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Root")
public class Root {
@XmlElements({
@XmlElement(name="Child", type=ChildImpl.class),
@XmlElement(name="Child", type=ChildImpl2.class)
})
protected List<AbstractChild> children;
public List<AbstractChild> getChildren() {
if (children == null) {
children = new ArrayList<AbstractChild>();
}
return this.children;
}
}
@XmlTransient
public abstract class AbstractChild {
@XmlElement(name = "Other", required = true)
protected List<Other> others; // class Other is not important for my question, so I'll skip its implementation details
public List<Other> getOthers() {
if (others == null) {
others = new ArrayList<Other>();
}
return this.others;
}
}
@XmlRootElement(name = "Child")
public class ChildImpl extends AbstractChild {
// custom behavior
}
@XmlRootElement(name = "Child")
public class ChildImpl2 extends AbstractChild {
// different custom behavior
}
然后,我有一个执行解组的类:
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
result = (Root) jaxbUnmarshaller.unmarshal(new ByteArrayInputStream(fileContent)); // where fileContent is an instance of byte[]
现在,根据我们的上下文,我希望unmarshaller为Root对象使用Child的特定实现......但这就是我正在努力的地方:我不知道如何通知unmarshaller使用特定的子类对于Child(在我们的文件中,Root,Child和Other的结构总是相同的。但是,我们如何处理Child取决于每个文件的源文件夹)。 我在创建上下文时尝试传递具体类 - 出于测试目的 - (例如JAXBContext.newInstance(Root.class,ChildImpl.class)),但由于某种原因,unmarshaller总是解析为最后输入的类@XmlElements数组(在本例中为ChildImpl2)。
我也尝试删除@XmlElements注释,但unmarshaller不知道处理Version元素,因为父类是抽象的(这也是我添加@XmlTransient注释的原因;我没有兴趣试图实例AbstractChild)
有什么想法吗? 提前谢谢!
答案 0 :(得分:1)
如果xml文件中的结构总是相同的,那么使用抽象类AbstractChild是没有意义的(在我看来)。逻辑应该在你的代码中的其他地方,策略或类似的东西中。
但它有可能:
有一个代表孩子的XmlElement。
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "child")
public class Child {
@XmlElement(name = "name")
private String name;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
有另一个类,如MyAbstractChild
public abstract class MyAbstractChild {
private final Child child;
public AbstractChild(final Child child) {
this.child = child;
}
public Child getChild() {
return child;
}
}
您想要的每个行为的子类:
public class MyChildImpl extends MyAbstractChild {
public MyChildImpl(final Child child) {
super(child);
}
// custom behavior here
}
然后你可以实现一个XmlAdapter:
public class MyChildImpAdapter extends XmlAdapter<Child, MyAbstractChild> {
private final Class<? extends AbstractChild> implClass;
public MyChildImpAdapter(final Class<? extends MyAbstractChild> implClass){
this.implClass = implClass;
}
@Override
public MyAbstractChild unmarshal(final Child child) throws Exception {
if (MyChildImpl.class.equals(this.implClass)) {
return new MyChildImpl(child);
} else {
return new MyChildImpl2(child);
}
}
@Override
public Child marshal(final MyAbstractChild abstractChild) throws Exception {
return abstractChild.getChild();
}
}
现在,您可以在根元素中使用新类型MyAbstractChild:
@XmlJavaTypeAdapter(value = MyChildImpAdapter.class)
protected List<MyAbstractChild> children;
最后,您可以训练unmarshaller使用您选择的适配器:
final JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
jaxbUnmarshaller.setAdapter(MyChildImpAdapter.class, new MyChildImpAdapter(MyChildImpl.class));
final InputStream inputStream = getClass().getResourceAsStream("some.xml");
final Root root = (Root) jaxbUnmarshaller.unmarshal(inputStream);
现在,你的孩子们已经拥有了带有MyChildImpl-Objects的Root-Element。
但正如我在开头写的那样:应该有另一种选择:)