@XmlRegistry-как это работает?
Я нашел несколько примеров JAXB2 @XmlRegistry
через интернет, но нет хороших углубленных учебников, которые говорят о концепции использования @XmlRegistry
С @XmlElementDecl
интересно, если его концепция не исследован вообще.
в любом случае вот мой вопрос, сначала некоторые примеры классов, которые я использую для unmarshall xml с помощью JAXB:
основной класс я пытаюсь unmarshal с помощью 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<Address> 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<Address> getAddresses() {
return addresses;
}
public void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
@SuppressWarnings("unused")
@XmlRegistry
public static class XMLObjectFactory {
@XmlElementDecl(scope = Employee.class, name= "id")
JAXBElement<String> createEmployeeId(String value) {
return new JAXBElement<String>(new QName("id"), String.class, "100");
}
@XmlElementDecl(scope = Employee.class, name= "name")
JAXBElement<String> createName(String value) {
return new JAXBElement<String>(new QName("name"), String.class, "Fake Name");
}
@XmlElementDecl(scope = Employee.class, name= "email")
JAXBElement<String> createEmail(String value) {
return new JAXBElement<String>(new QName("email"), String.class, value);
}
@XmlElementDecl(scope = Employee.class, name= "addresses")
JAXBElement<List> createAddresses(List value) {
return new JAXBElement<List>(new QName("addresses"), List.class, value);
}
}
}
дочерний класс - Адрес.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<String> createAddressLine1(String value) {
return new JAXBElement<String>(new QName("addressLine1"), String.class, value);
}
@XmlElementDecl(scope = Employee.class, name= "addressLine2")
JAXBElement<String> createAddressLine2(String value) {
return new JAXBElement<String>(new QName("addressLine2"), String.class, value);
}
@XmlElementDecl(scope = Employee.class, name= "addressLine3")
JAXBElement<String> createAddressLine3(String value) {
return new JAXBElement<String>(new QName("addressLine3"), String.class, value);
}
}
}
XML, чтобы быть неупорядоченными - работника.в XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<id>1</id>
<name>Vaishali</name>
<email>Vaishali@example.com</email>
<addresses>
<address>
<addressLine1>300</addressLine1>
<addressLine2>Mumbai</addressLine2>
<addressLine3>India</addressLine3>
</address>
<address>
<addressLine1>301</addressLine1>
<addressLine2>Pune</addressLine2>
<addressLine3>India</addressLine3>
</address>
</addresses>
</employee>
Unmarshalling Код:
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);
}
}
когда я unmarshal XML сотрудника, используя выше код, список адресов не заполняется. Результирующий объект employee имеет только пустой список адресов. Что-то не так с моими картами?
чтобы узнать, что происходит, и посмотреть, действительно ли объекты employee создаются с помощью фабрики объектов (имея аннотация @XMLRegistry), я изменил значение id и name в заводских методах, однако это не повлияло на выходные данные, что говорит мне, что JAXB фактически не использует ObjectFactory, почему?
Я собираюсь все это неправильно? Любая помощь будет оценена.
2 ответов
@XmlRegistry-как это работает?
@XmlRegistry
используется для обозначения класса, который имеет @XmlElementDecl
Примечание. Чтобы ваш процесс реализации JAXB этого класса, вам нужно убедиться, что он включен в список классов, используемых для начальной загрузки JAXBContext
. Недостаточно, чтобы это был статический внутренний класс одного из ваших классов модели домена:
JAXBContext context = JAXBContext.newInstance(Employee.class, Employee.XMLObjectFactory.class);
@XmlElementDecl - как это работает?
если значение поля / свойства будет равно JAXBElement
тогда вам нужно использовать @XmlElementDecl
. А JAXBElement
собирает информацию, которая может быть полезна:
- имя элемента, это необходимо, если вы сопоставляете структуру выбора, где несколько элементов одного типа. Если имя элемента не соответствует уникальному типу, вы не сможете обойти документ туда и обратно.
-
JAXBElement
может использоваться для представления элемента сxsi:nil="true"
.
XmlObjectFactory
@XmlElementDecl
также позволяет указать область. Я немного изменил модель с вашего поста. Я представил XmlObjectFactory
класс, который имеет два @XmlElementDecl
. Оба указывают имя address
. Я использовал scope
свойства, так что для свойства Employee
класс @XmlElementDecl
соответствующую Address
класс с использованием.
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<Address> createAddress(Address value) {
return new JAXBElement<Address>(new QName("address"), Address.class, value);
}
@XmlElementDecl(name = "address")
JAXBElement<String> createStringAddress(String value) {
return new JAXBElement<String>(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<JAXBElement<Address>> 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<JAXBElement<Address>> getAddresses() {
return addresses;
}
public void setAddresses(List<JAXBElement<Address>> 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
, поэтому я сосредоточусь на следующей части вашего поста:
когда я unmarshal работник xml, используя выше код, список адресов не заполняется. Результирующий объект employee имеет только пробел список адресов. Что-то не так с моими картами?
список 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<Address> 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<Address> getAddresses() {
return addresses;
}
public void setAddresses(List<Address> 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);
}
}
вход.xml / Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<id>1</id>
<name>Vaishali</name>
<email>Vaishali@example.com</email>
<addresses>
<address>
<addressLine1>300</addressLine1>
<addressLine2>Mumbai</addressLine2>
<addressLine3>India</addressLine3>
</address>
<address>
<addressLine1>301</addressLine1>
<addressLine2>Pune</addressLine2>
<addressLine3>India</addressLine3>
</address>
</addresses>
</employee>
вы должны взять объект списка адреса. В этом объекте вам нужно будет добавить объект, содержащий такие данные, как addressline1. addressline2 и так далее.
i.e.
List addrObjList = new List();
addrObjList.add(object); // Bind an object containing data and add one by one