使用 JAXB 支持具有微小变化的模式 [英] Using JAXB to support schemas with minor variations

查看:20
本文介绍了使用 JAXB 支持具有微小变化的模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况

我需要支持基于模式生成 XML 文档,这些模式彼此之间仅略有不同.具体来说,我需要支持的模式基于行业标准,随着时间的推移会略有变化,供应商可能会制作自己的定制版本.

I need to support generating XML documents based on schemas that vary only slightly between each other. Specifically, the schemas that I need to support are based on industry standards that change slightly over time and vendors may make their own customized version of them.

问题

我打算使用带有继承的 JAXB 2(来自 Metro)作为解决方案.我希望包结构最终是这样的:

I was intending to use JAXB 2 (from Metro) with inheritance as a solution. I expected the package structure to end up something like this:

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

v2 包中的类将简单地扩展 v1 包中的类并根据需要覆盖.不幸的是,该计划最终无法实现,因为子类无法覆盖父类中的注释(参见此处).例如,如果架构中的属性在版本之间重命名,则 v2 元素类将不得不完全重新实现该元素,而不是从 v1 继承.

Where the classes in the v2 package would simply extend the classes in the v1 package and override as necessary. Unfortunately, that plan ended up being impossible since subclasses cannot overwrite the annotations in parent classes (see here). For example, if an attribute in a schema was renamed between versions, then the v2 element class would have to completely re-implement the element without inheriting from the v1.

所以就我所知,这让我只有两个选择

So that leaves me with only two options as far as I can tell

选项 1

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

Create a "base" package for each schema type, annotate the element classes in that package with @XmlAccessorType(XmlAccessType.NONE), and remove all other annotations. Then, in each versioned package create classes that subclass the corresponding class in the "base" package and add all the required annotations. This solution does give me a little help in the inheritance realm, but code duplication is huge and it would be a challenge to maintain.

选项 2

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

Don't use JAXB. I really don't like this solution since I'd also like to work with JAX-RS/JAX-WS.

问题

  • 我应该如何使用 JAXB 来支持具有微小变化的多个模式,而不会有一堆代码重复?
  • 是否有我应该考虑的不同技术组合?

编辑

以下来自 Blaise 的解决方案对于我们的大多数模式都非常有效,这些模式只是彼此之间的微小转换,通常具有相同的数据.然而,我们遇到了一个问题,在这种情况下,使用带有包名的继承来进行版本控制更有意义.例如:

The solution below from Blaise worked perfectly for most of our schemas which were just a minor translation of each other with generally the same data. However, we ran into a problem in cases where it made more sense to use inheritance with package names for versioning. For Example:

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

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

(where v2.ElementA extends v1.ElementA)

在这种情况下使用 MOXy 的 OXM 会遇到一个错误,解决方法可以在此处(使用 Blaise 提供的解决方案,不少于!)

Using MOXy's OXM in this case stumbles across a bug and the workaround can be found here (with the solution provided by Blaise, no less!)

推荐答案

注意:我是EclipseLink JAXB (MOXy) 领导和成员 JAXB 2 (JSR-222) 专家组.

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

您可以使用 EclipseLink JAXB 中的外部绑定文档来映射 XML 模式之间的变化.

You could use the external binding document in EclipseLink JAXB to map the variations among XML Schemas.

供应商 1

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

You could use the standard JAXB annotations to map one of the vendors:

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 属性:

We will use MOXy's external metadata to customize the metadata provided by annotations. In the document (oxm-v2.xml) below we will map the firstName and lastName properties to XML Attributes:

<?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 元素.

Again we will use MOXy's external binding document (oxm-v3.xml) to override the annotations. This time we will make the id property an XML element.

<?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>

演示

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

The sample code below demonstrates to specify the external metadata. Note how I introduced a fourth vendor to show that the external metadata documents can be combined.

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 文档.

Below is the output from each of the vendors. Remember that the same instance of Customer was used to make each of these XML documents.

<?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>

了解更多信息

这篇关于使用 JAXB 支持具有微小变化的模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆