Java 使用JAXB支持具有微小变化的模式
形势 我需要支持基于模式生成XML文档,这些模式之间的差异很小。具体地说,我需要支持的模式是基于行业标准的,随着时间的推移,这些标准会发生轻微的变化,供应商可能会为其定制自己的版本 问题 我打算使用JAXB2(来自Metro)和继承作为解决方案。我希望包结构最终会是这样的:Java 使用JAXB支持具有微小变化的模式,java,design-patterns,xml-serialization,schema,jaxb2,Java,Design Patterns,Xml Serialization,Schema,Jaxb2,形势 我需要支持基于模式生成XML文档,这些模式之间的差异很小。具体地说,我需要支持的模式是基于行业标准的,随着时间的推移,这些标准会发生轻微的变化,供应商可能会为其定制自己的版本 问题 我打算使用JAXB2(来自Metro)和继承作为解决方案。我希望包结构最终会是这样的: com.company.xml.schema.v1 com.company.xml.schema.v2 com.company.xml.schema.v2.vendorxyz 其中v2包中的类只需扩
com.company.xml.schema.v1
com.company.xml.schema.v2
com.company.xml.schema.v2.vendorxyz
其中v2包中的类只需扩展v1包中的类,并根据需要进行重写。不幸的是,由于子类无法覆盖父类()中的注释,因此该计划最终不可能实现。例如,如果模式中的某个属性在不同版本之间重命名,那么v2元素类必须完全重新实现该元素,而不从v1继承
因此,就我所知,我只有两个选择
选择1
为每个模式类型创建一个“基本”包,用@xmlacessortype(xmlacesstype.NONE)注释该包中的元素类,并删除所有其他注释。然后,在每个版本化包中创建类,这些类在“base”包中为相应的类创建子类,并添加所有必需的注释。这个解决方案在继承领域确实给了我一点帮助,但是代码重复是巨大的,维护它将是一个挑战
选择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中的外部绑定文档来映射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
)中,我们将把firstName
和lastName
属性映射到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>
演示
下面的示例代码演示如何指定外部元数据。请注意,我是如何引入第四个供应商来显示外部元数据文档可以合并的
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();
}
}
了解更多信息
JAXBContextFactory.eclipseelink\u OXM\u XML\u KEY
被JAXBContextProperties.OXM\u METADATA\u SOURCE
取代。
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();
}
}
<?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>