当前位置: 首页 > 面试题库 >

使用JAXB支持具有微小变化的模式

华景焕
2023-03-14
问题内容

情况

我需要支持基于彼此之间仅稍有不同的架构生成XML文档。具体来说,我需要支持的架构是基于行业标准的,该行业标准会随着时间的流逝而略有变化,并且供应商可能会制定自己的定制版本。

问题

我打算将带有继承的JAXB 2(来自Metro)用作解决方案。我期望包结构最终像这样:

    com.company.xml.schema.v1
    com.company.xml.schema.v2
    com.company.xml.schema.v2.vendorxyz

v2包中的类将仅扩展v1包中的类,并在必要时进行覆盖。不幸的是,该计划最终变得不可能,因为子类无法覆盖父类中的注释(请参见此处)。例如,如果在两个版本之间重命名了架构中的属性,则v2元素类将必须完全重新实现该元素,而不能从v1继承。

据我所知,这只剩下两个选择

选项1

为每种模式类型创建一个“基础”包,用@XmlAccessorType(XmlAccessType.NONE)注释该包中的元素类,并删除所有其他注释。然后,在每个版本化的程序包中创建在“基本”程序包中子类化相应类的类,并添加所有必需的注释。这个解决方案确实在继承领域给了我一些帮助,但是代码重复很大,并且维护起来很困难。

选项2

不要使用JAXB。我真的不喜欢这种解决方案,因为我也想使用JAX-RS / JAX-WS。

问题

  • 我应该如何使用JAXB来支持具有微小变化的多个模式,而无需进行大量代码重复?
  • 我应该考虑其他不同的技术组合吗?

编辑

Blaise的以下解决方案非常适合我们的大多数模式,这些模式只是使用相同的数据相互之间的较小转换。但是,在使用继承和程序包名称进行版本控制更有意义的情况下,我们遇到了一个问题。例如:

com.company.xml.schema.v1.ElementA
com.company.xml.schema.v2.ElementA

(其中v2.ElementA扩展了v1.ElementA)

在这种情况下使用MOXy的OXM会偶然发现一个错误,并且可以在此处找到解决方法(使用Blaise提供的解决方案!)


问题答案:

注意: 我是 EclipseLink
JAXB(MOXy)的
负责人,并且是 JAXB
2(JSR-222)
专家组的成员。

您可以使用EclipseLink JAXB中的外部绑定文档来映射XML模式之间的差异。

供应商1

您可以使用标准的JAXB批注来映射供应商之一:

package forum9419732;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {

    @XmlAttribute
    private int id;

    private String lastName;
    private String firstName;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

供应商2

我们将使用MOXy的外部元数据来自定义注释提供的元数据。在oxm-v2.xml下面的文档()中,我们将firstNamelastName属性映射到XML属性:

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum9419732">
    <java-types>
        <java-type name="Customer">
            <java-attributes>
                <xml-attribute java-attribute="firstName"/>
                <xml-attribute java-attribute="lastName"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

供应商3

同样,我们将使用MOXy的外部绑定文档(oxm-v3.xml)覆盖注释。这次,我们将使id属性成为XML元素。

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum9419732">
    <java-types>
        <java-type name="Customer">
            <java-attributes>
                <xml-element java-attribute="id" name="identifier"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

演示版

下面的示例代码演示了如何指定外部元数据。请注意,我是如何引入第四家供应商来表明可以组合外部元数据文档的。

package forum9419732;

import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

public class Demo {

    public static void main(String[] args) throws JAXBException {
        Customer customer = new Customer();
        customer.setId(123);
        customer.setFirstName("Jane");
        customer.setLastName("Doe");

        // VENDOR 1
        JAXBContext jcV1 = JAXBContext.newInstance(Customer.class);
        marshal(jcV1, customer);

        // VENDOR 2
        Map<String, Object> propertiesV2 = new HashMap<String, Object>(1);
        propertiesV2.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum9419732/oxm-v2.xml");
        JAXBContext jcV2 = JAXBContext.newInstance(new Class[] {Customer.class}, propertiesV2);
        marshal(jcV2, customer);

        // VENDOR 3
        Map<String, Object> propertiesV3 = new HashMap<String, Object>(1);
        propertiesV3.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum9419732/oxm-v3.xml");
        JAXBContext jcV3 = JAXBContext.newInstance(new Class[] {Customer.class}, propertiesV3);
        marshal(jcV3, customer);

        // VENDOR 4
        Map<String, Object> propertiesV4 = new HashMap<String, Object>(1);
        List<String> oxmV4 = new ArrayList<String>(2);
        oxmV4.add("forum9419732/oxm-v2.xml");
        oxmV4.add("forum9419732/oxm-v3.xml");
        propertiesV4.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, oxmV4);
        JAXBContext jcV4 = JAXBContext.newInstance(new Class[] {Customer.class}, propertiesV4);
        marshal(jcV4, customer);
    }

    private static void marshal(JAXBContext jc, Customer customer) throws JAXBException {
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
        System.out.println();
    }

}

输出量

以下是每个供应商的输出。请记住,使用的相同实例Customer来制作每个这些XML文档。

<?xml version="1.0" encoding="UTF-8"?>
<customer id="123">
   <lastName>Doe</lastName>
   <firstName>Jane</firstName>
</customer>

<?xml version="1.0" encoding="UTF-8"?>
<customer id="123" lastName="Doe" firstName="Jane"/>

<?xml version="1.0" encoding="UTF-8"?>
<customer>
   <identifier>123</identifier>
   <lastName>Doe</lastName>
   <firstName>Jane</firstName>
</customer>

<?xml version="1.0" encoding="UTF-8"?>
<customer lastName="Doe" firstName="Jane">
   <identifier>123</identifier>
</customer>

想要查询更多的信息

  • http://blog.bdoughan.com/search/label/jaxb.properties
  • http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
  • http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html


 类似资料:
  • 问题内容: 我有一个定义元素和属性默认值的架构。我正在尝试使用基于该架构的JAXB解析文档,但是JAXB没有设置默认值。关于如何使JAXB接受模式中的默认值的任何想法? example.xsd: example1.xml TestParser.java RootElement.java ChildEl.java 问题答案: 元素默认值 要获取element属性的默认值,您需要对其进行如下注释: 属

  • 问题内容: 因此,我希望将其转换为这样的Java代码: JAXB是否可能? 曾经看到一些WebService Client存根生成器正在执行此操作,但也许不确定axis2 Webservice。 问题答案: 的 JAXB(JSR-222) 规范没有盖产生快速失败逻辑到域模型。现在,一种常见的做法是以注释(或XML)的形式表示验证规则,并对它们进行验证。 Bean验证(JSR-303) 对此进行了标

  • 问题内容: 我想从网站上获取一些数据。通常,我使用这些东西,但是现在该站点使用JS来提供数据。las,不支持。 我该怎么用呢? 问题答案: 以下是一些选项: 硒(教程) 对于无头自动化,可以将Selenium与PhantomJS结合使用 WebKit 蜘蛛猴

  • 我想解封一个包含混合内容的XML文件。我在stackoverflow上发现了一个似乎合适的线程(JAXB-@XmlMixed用于读取@XmlValue和@XmlElement),其中用户bdoughan定义了3个用例来处理混合内容。 第三个用例将标签之间的文本保存在单个 String 变量中,并将元素保存在 List 中。这就是我想要的。不幸的是,我无法让它工作,线程很旧,也许已经过时了。 我已经

  • 问题内容: 我正在使用Swing进行工作,但它不支持Javascript或某些高级标签(如etc),也不支持颜色,字体大小等。 有什么解决方案可以使编辑器窗格可以显示HTML文件,就像在普通HTML浏览器中显示的一样? 问题答案: 当前仅支持(最高),对的支持减少, 对于并且相当完整的使用, 有一些自定义Java库,具有对HTML4 / 5,css和js的(full ???)支持,但我建议改用

  • 问题内容: 使用python函数调整显示分辨率的大小。它应该是跨平台的,即支持Windows,Linux和Mac(根据操作系统的不同,可以有多种情况) 我有我认为可以在linux(Ubuntu)上运行的代码,我正在寻找Windows和Mac的解决方案(应同时支持32位和64位计算机) 如果有人能告诉我如何获得Windows和Mac的可能的显示分辨率,我也将不胜感激 我在linux上的功能是这样的: