@XmlRegistry – 它是如何工作的?

我在互联网上找到了一些JAXB2 @XmlRegistry例子,但是没有很好的深入教程讨论将@XmlRegistry@XmlElementDecl一起使用的概念,想知道它的概念是否在一般情况下没有多少探讨。

无论如何这里是我的问题,首先是一些我用来使用JAXB解组xml的示例类:

我正在尝试使用JAXB解组的主要类 – Employee.java

 package com.test.jaxb; import java.util.List; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlElementDecl; import javax.xml.bind.annotation.XmlRegistry; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import com.test.jaxb.dto.Address; @XmlRootElement public class Employee { private int id; private String name; private String email; private List
addresses; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public List
getAddresses() { return addresses; } public void setAddresses(List
addresses) { this.addresses = addresses; } @SuppressWarnings("unused") @XmlRegistry public static class XMLObjectFactory { @XmlElementDecl(scope = Employee.class, name= "id") JAXBElement createEmployeeId(String value) { return new JAXBElement(new QName("id"), String.class, "100"); } @XmlElementDecl(scope = Employee.class, name= "name") JAXBElement createName(String value) { return new JAXBElement(new QName("name"), String.class, "Fake Name"); } @XmlElementDecl(scope = Employee.class, name= "email") JAXBElement createEmail(String value) { return new JAXBElement(new QName("email"), String.class, value); } @XmlElementDecl(scope = Employee.class, name= "addresses") JAXBElement createAddresses(List value) { return new JAXBElement(new QName("addresses"), List.class, value); } } }

子类 – Address.java

 package com.test.jaxb.dto; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlElementDecl; import javax.xml.bind.annotation.XmlRegistry; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import com.test.jaxb.Employee; @XmlRootElement public class Address { private String addressLine1; private String addressLine2; private String addressLine3; public String getAddressLine1() { return addressLine1; } public void setAddressLine1(String addressLine1) { this.addressLine1 = addressLine1; } public String getAddressLine2() { return addressLine2; } public void setAddressLine2(String addressLine2) { this.addressLine2 = addressLine2; } public String getAddressLine3() { return addressLine3; } public void setAddressLine3(String addressLine3) { this.addressLine3 = addressLine3; } @SuppressWarnings("unused") @XmlRegistry private static class XMLObjectFactory { @XmlElementDecl(scope = Employee.class, name= "addressLine1") JAXBElement createAddressLine1(String value) { return new JAXBElement(new QName("addressLine1"), String.class, value); } @XmlElementDecl(scope = Employee.class, name= "addressLine2") JAXBElement createAddressLine2(String value) { return new JAXBElement(new QName("addressLine2"), String.class, value); } @XmlElementDecl(scope = Employee.class, name= "addressLine3") JAXBElement createAddressLine3(String value) { return new JAXBElement(new QName("addressLine3"), String.class, value); } } } 

要解组的xml – employee.xml

   1 Vaishali Vaishali@example.com  
300 Mumbai India
301 Pune India

解组编码:

 package com.test.jaxb; import java.io.FileReader; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; public class ObjectFactoryTest { public static void main(String[] args) throws Exception { FileReader reader = new FileReader("resources/employee.xml"); JAXBContext context = JAXBContext.newInstance(Employee.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Object obj = unmarshaller.unmarshal(reader); System.out.println(obj); } } 

当我使用上面的代码解组员工xml时,地址列表不会被填充。 生成的员工对象只有一个空白的地址列表。 我的映射有什么问题吗?

要找出正在发生的事情并查看是否实际使用Object Factory创建了雇员对象(具有@XMLRegistry注释),我在工厂方法中更改了id和name的值,但这对输出没有影响,这告诉我JAXB实际上并没有使用ObjectFactory,为什么?

我完全错了吗? 任何帮助,将不胜感激。

@XmlRegistry – 它是如何工作的?

@XmlRegistry用于标记具有@XmlElementDecl注释的类。 要让您的JAXB实现处理此类,您需要确保它包含在用于引导JAXBContext的类列表中。 它是一个域模型类的静态内部类是不够的:

 JAXBContext context = JAXBContext.newInstance(Employee.class, Employee.XMLObjectFactory.class); 

@XmlElementDecl – 它是如何工作的?

如果field / property的值将是JAXBElement那么您需要利用@XmlElementDeclJAXBElement捕获可能有用的信息:

  • 元素名称,如果要映射到多个元素属于同一类型的选择结构,则必须执行此操作。 如果元素名称不对应于唯一类型,那么您将无法往返文档。
  • JAXBElement可用于表示xsi:nil="true"的元素。

XmlObjectFactory

@XmlElementDecl还允许您指定范围。 我已经修改了你的模型。 我已经介绍了一个有两个@XmlElementDeclXmlObjectFactory类。 两者都指定address名称。 我已经利用了scope属性,因此对于Employee类中的属性,可以使用与Address类对应的@XmlElementDecl

 package forum11078850; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlElementDecl; import javax.xml.bind.annotation.XmlRegistry; import javax.xml.namespace.QName; @XmlRegistry public class XmlObjectFactory { @XmlElementDecl(scope = Employee.class, name = "address") JAXBElement
createAddress(Address value) { return new JAXBElement
(new QName("address"), Address.class, value); } @XmlElementDecl(name = "address") JAXBElement createStringAddress(String value) { return new JAXBElement(new QName("address"), String.class, value); } }

雇员

@XmlElementRef注释将使属性的值与其根元素名称匹配。 可能的匹配将包括使用@XmlRootElement@XmlElementDecl映射的类。

 package forum11078850; import java.util.List; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.*; @XmlRootElement @XmlType(propOrder = { "id", "name", "email", "addresses" }) public class Employee { private int id; private String name; private String email; private List> addresses; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @XmlElementWrapper @XmlElementRef(name="address") public List
> getAddresses() { return addresses; } public void setAddresses(List
> addresses) { this.addresses = addresses; } }

ObjectFactoryTest

 package forum11078850; import java.io.FileReader; import javax.xml.bind.*; public class ObjectFactoryTest { public static void main(String[] args) throws Exception { FileReader reader = new FileReader("src/forum11078850/input.xml"); JAXBContext context = JAXBContext.newInstance(Employee.class, XmlObjectFactory.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Object obj = unmarshaller.unmarshal(reader); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(obj, System.out); } } 

我的原始答案中的Address类和input.xml可用于运行此示例。


原始答案

我不确定你是如何尝试使用@XmlRegistry ,所以我将重点关注你post的以下部分:

当我使用上面的代码解组员工xml时,地址列表不会被填充。 生成的员工对象只有一个空白的地址列表。 我的映射有什么问题吗?

您的Address对象列表包含在分组元素( addresses )中,因此您需要使用@XmlElementWrapper批注来映射此用例。 以下是一个完整的例子:

雇员

 package forum11078850; import java.util.List; import javax.xml.bind.annotation.*; @XmlRootElement @XmlType(propOrder = { "id", "name", "email", "addresses" }) public class Employee { private int id; private String name; private String email; private List
addresses; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @XmlElementWrapper @XmlElement(name = "address") public List
getAddresses() { return addresses; } public void setAddresses(List
addresses) { this.addresses = addresses; } }

地址

 package forum11078850; public class Address { private String addressLine1; private String addressLine2; private String addressLine3; public String getAddressLine1() { return addressLine1; } public void setAddressLine1(String addressLine1) { this.addressLine1 = addressLine1; } public String getAddressLine2() { return addressLine2; } public void setAddressLine2(String addressLine2) { this.addressLine2 = addressLine2; } public String getAddressLine3() { return addressLine3; } public void setAddressLine3(String addressLine3) { this.addressLine3 = addressLine3; } } 

ObjectFactoryTest

 package forum11078850; import java.io.FileReader; import javax.xml.bind.*; public class ObjectFactoryTest { public static void main(String[] args) throws Exception { FileReader reader = new FileReader("src/forum11078850/input.xml"); JAXBContext context = JAXBContext.newInstance(Employee.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Object obj = unmarshaller.unmarshal(reader); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(obj, System.out); } } 

input.xml中/输出

   1 Vaishali Vaishali@example.com  
300 Mumbai India
301 Pune India

您必须获取Address的List对象。 在该对象中,您必须添加包含addressline1等数据的对象。 地址线2等。

  ie List addrObjList = new List(); addrObjList.add(object); // Bind an object containing data and add one by one