java - 如何让 JAXB 在解码期间将我的子类之一用于非根元素?

标签 java jaxb

我已经阅读了有关此主题的所有问题,但没有一个与我的问题相关。我有这些类(每个类都在自己的文件中):

@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/

相关文章:

Java 程序仅适用于 Netbeans 中的断点

java - 使用运行时参数创建单例 bean

java - Jersey 不解码 Java 泛型类型

java - Jersey REST 服务 - Tomcat 中的 404 响应

java - 为什么Java中Runtime.getRuntime().exec()找不到 "chgport.exe"?

java - 迭代列表并将 Callables 提交到 ExecutorService

java - 如何使用 JAXB Moxy 解码具有未命名字段的 JSON

java - 使用 jaxb 时出现编码(marshal)异常

java - 如何在 JAXB 中设置非命名空间的 nil 和数据类型属性

java - 向继承方法添加注释的最佳方法