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

在使用JAXB时,如何使XML仅包含子类的标记?

须旭
2023-03-14

我有一些Java类扩展了一个公共超类。我想用JAXB对它们进行封送/解封,而不会在XML表示中看到超类标记。包含超类的模块不知道当前上下文中可用的子类。

以下是我试图做的事情和我的方法的最小例子:

示例XML:

<root>
   <instance>
       <member>foo</member>
   </instance>
</root>

这应该是一个等效的 Java 表示形式,其中具有超类类型的成员,该成员是实例的父

Root root = new Root();
Instance instance = new Instance();
instance.setMember("foo");
root.setSuperclass(instance);

我主要关心的是从XML表示到Java对象。请注意,我明确不想在XML文件中编写超类标记,因此类似于的内容。

我目前的实现:

@XmlRootElement
class Root {
    private Superclass superclass;

    @XmlAnyElement
    Superclass getSuperclass() { return superclass; }
    void setSuperclass(Superclass superclass) { this.superclass = superclass; }
}

@XmlJavaTypeAdapter(ValueAdapter.class)
class Superclass {}

@XmlRootElement(name = "instance")
class Instance extends Superclass {
    private String member;

    @XmlElement
    public String getMember() {return member;}
    public void setMember(String member) {this.member = member;}
}

class ValueAdapter extends XmlAdapter<Object, Superclass> {
    @Override
    public Object marshal(Superclass v) {
        return v;
    }
    @Override
    public Superclass unmarshal(Object v) {
        Element element = (Element) v;
        if (element.getNodeName().equals("instance")) {
            Instance instance = new Instance();
            instance.setMember(element.getTextContent());
            return instance;
        }
        else throw new IllegalArgumentException();
    }
}

在这个例子中,我为Instance硬编码了解组method,但稍后它将访问一个可以注册多个子类的服务。

上面的方法有点用,但看起来完全不对。通过深入Node手动解组子类对象真的很难看。毕竟,我不是在使用JAXB来隐藏这种XML树遍历吗?如果子类有多个成员,比纯字符串更复杂,情况会变得更糟。我对JAXB很陌生,所以我认为我要么滥用了框架,要么忽略了一些显而易见的东西。有什么建议吗?


共有2个答案

邹书
2023-03-14
匿名用户

实际上,有一个更简单的解决方案,不需要任何人工干预,即< code>@XmlElementRef:

@XmlRootElement
class Root {
    private Superclass superclass;

    @XmlElementRef
    Superclass getSuperclass() { return superclass; }
    void setSuperclass(Superclass superclass) { this.superclass = superclass; }
}

超类不需要任何注释,尤其是不需要转换器。

东方华晖
2023-03-14

毕竟我已经找到了一个合理的解决方案。这个想法实际上是让JAXB继续发挥它的魔力,但从实例作为新的根元素开始:

    public Superclass unmarshal(Object v) throws JAXBException {
        Element element = (Element) v;

        JAXBContext jc = JAXBContext.newInstance(Instance.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        return unmarshaller.unmarshal(element, Instance.class).getValue();
    }

当然,在实际应用程序中创建新上下文的成本很高,不应该每次都重做,但上下文将由了解所有可用实例的提供者外部提供,如下所示:

    public Superclass unmarshal(Object v) throws JAXBException {
        Element element = (Element) v;
        String tag = element.getNodeName();

        Class<? extends Superclass> clazz = instanceProvider.getClassForXmlTag(tag);
        JAXBContext jc = instanceProvider.getJaxbContextForXmlTag(tag);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        return unmarshaller.unmarshal(element, clazz).getValue();
    }
 类似资料:
  • 问题内容: 考虑这个例子- 我有一个称为Report的类,该类具有Message类型的字段。Message类具有一个称为“ body”的字段,该字段是一个字符串。“ body”可以是任何字符串, 但有时包含格式正确的XML内容 。如何确保当“正文”包含XML内容时,序列化采用XML结构的形式而不是当前的结构? 这是带有输出的代码- 报告 类别 讯息 类别 主要 输出如下- 如您在上面的输出中看到的

  • 我有一个需求,需要从JAXB生成XML。我使用了基本对象,其中只有具有父子关系的键值对,但从未遇到过下面这样的情况。预期的XML 在Java对象中,我不知道如何使用特殊字符

  • 我陷入了一个棘手的问题,我应该使用JAXB库取消marshaX输入流,除了XML结构没有帮助。 我的问题是:标记用于值为>的的

  • 我的真实案例使用了大量具有大量属性的类,版本控制的数量可能是一个很大的数字。我希望存储每个版本的XSD,并通过动态指定包含版本号的XSD名称从Java类生成XMLs。 有没有可能实现我上面描述的需求,或者你有一个类似的解决方案来满足我的需求?

  • 我已经生成java类使用从一个xsd,其中根元素是类型的。 jaxb生成的根元素是 当我尝试解组与该xsd对应的xml并强制转换JaxbElement时,它会引发一个强制转换异常: 片段:

  • 我正在使用JAXB来生成一个肥皂xml请求。我想要的当前xml输出是这个 到目前为止,我已经生成了信封和标题标签,但我有安全标签的问题。 我的问题是,如果我尝试将xmlns设置为package-info.class前缀是正确的,但是和转到根元素(信封)而不是安全标记。这是我得到的输出: 正如您在所需的 xml 输出中看到的 和 命名空间位于安全标记处。如何才能将这些xmlns添加到安全标签?以及用