我已经阅读了有关此主题的所有问题,但没有一个与我的问题相关。我有这些类(每个类都在自己的文件中):
@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[]
现在,根据我们的上下文,我希望解码器为 Root 对象使用 Child 的特定实现...但这就是我苦苦挣扎的地方:我不知道如何指示解码器使用特定的子类对于 Child(在我们的文件中,Root、Child 和 Other 的结构始终相同。但是,我们如何处理 Child 取决于每个文件的源文件夹)。 我尝试在创建上下文时传递具体类(仅用于测试目的)(例如 JAXBContext.newInstance(Root.class, ChildImpl.class)),但由于某种原因,解码器始终解析为最后输入的类@XmlElements 数组(在本例中为 ChildImpl2)。
我还尝试删除 @XmlElements 注释,但解码器不知道如何处理 Version 元素,因为父类是抽象的(这也是我添加 @XmlTransient 注释的原因;我对尝试实例 AbstractChild)
有什么想法吗? 提前致谢!
最佳答案
如果 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;
最后,您可以训练解码器使用您选择的适配器:
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。
但正如我在开头所写的:应该有另一种选择:)
关于java - 如何让 JAXB 在解码期间将我的子类之一用于非根元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32445468/