Tôi tự hỏi liệu có thể chú thích các lớp của tôi sao cho lần đầu tiên marshaller gặp một đối tượng, nó tạo ra một phần tử XML của kiểu thích hợp, nhưng bất kỳ tham chiếu tiếp theo nào đối tượng này bằng bất cứ thứ gì khác sẽ có một mục nhập IDREF XML tạo?JAXB có thể sắp xếp lại bằng cách ngăn chặn lúc đầu tiên, sau đó so sánh với @XmlIDREF để tham khảo tiếp theo không?
Trả lời
Bạn có thể tận dụng các khái niệm về JAXB của XmlAdapter
để làm một cái gì đó như sau:
input.xml
Sau đây là tài liệu XML tôi sẽ sử dụng ví dụ này. The 3rd phone-number
entry là một tham chiếu đến phone-number
mục 1 và thứ 5 phone-number
entry là một tham chiếu đến 4 .:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<phone-number id="A">
<number>555-AAAA</number>
</phone-number>
<phone-number id="B">
<number>555-BBBB</number>
</phone-number>
<phone-number id="A"/>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W">
<number>555-WORK</number>
<extension>1234</extension>
</phone-number>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/>
</customer>
khách hàng
Lớp khách hàng duy trì một tập hợp các đối tượng PhoneNumber
. Ví dụ tương tự của PhoneNumber có thể xuất hiện nhiều lần trong bộ sưu tập.
package forum7587095;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer {
private List<PhoneNumber> phoneNumbers;
@XmlElement(name="phone-number")
public List<PhoneNumber> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
}
PhoneNumber
Đây là một lớp học mà có thể xuất hiện trong tài liệu riêng của mình hoặc là một tài liệu tham khảo. Điều này sẽ được xử lý bằng cách sử dụng XmlAdapter
. Một XmlAdapter được cấu hình bằng cách sử dụng chú thích @XmlJavaTypeAdapter
. Vì chúng ta đã xác định bộ chuyển đổi này ở mức độ loại/lớp nó sẽ áp dụng cho tất cả các thuộc tính tham khảo lớp PhoneNumber
:
package forum7587095;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(PhoneNumberAdapter.class)
public class PhoneNumber {
private String id;
private String number;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public boolean equals(Object arg0) {
if(null == arg0 || arg0.getClass() != this.getClass()) {
return false;
}
PhoneNumber test = (PhoneNumber) arg0;
if(!equals(id, test.getId())) {
return false;
}
return equals(number, test.getNumber());
}
protected boolean equals(String control, String test) {
if(null == control) {
return null == test;
} else {
return control.equals(test);
}
}
@Override
public int hashCode() {
return id.hashCode();
}
}
WorkPhoneNumber
Dựa trên nhận xét của bạn tôi đã thêm một lớp con của PhoneNumber
.
package forum7587095;
public class WorkPhoneNumber extends PhoneNumber {
private String extension;
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
@Override
public boolean equals(Object arg0) {
if(!super.equals(arg0)) {
return false;
}
return equals(extension, ((WorkPhoneNumber) arg0).getExtension());
}
}
PhoneNumberAdapter
Dưới đây là việc thực hiện các XmlAdapter
. Lưu ý rằng chúng ta phải duy trì nếu đối tượng PhoneNumber đã được nhìn thấy trước đây. Nếu có, chúng tôi chỉ điền phần id
của đối tượng AdaptedPhoneNumber
.
package forum7587095;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{
private List<PhoneNumber> phoneNumberList = new ArrayList<PhoneNumber>();
private Map<String, PhoneNumber> phoneNumberMap = new HashMap<String, PhoneNumber>();
@XmlSeeAlso(AdaptedWorkPhoneNumber.class)
@XmlType(name="phone-number")
public static class AdaptedPhoneNumber {
@XmlAttribute public String id;
public String number;
public AdaptedPhoneNumber() {
}
public AdaptedPhoneNumber(PhoneNumber phoneNumber) {
id = phoneNumber.getId();
number = phoneNumber.getNumber();
}
public PhoneNumber getPhoneNumber() {
PhoneNumber phoneNumber = new PhoneNumber();
phoneNumber.setId(id);
phoneNumber.setNumber(number);
return phoneNumber;
}
}
@XmlType(name="work-phone-number")
public static class AdaptedWorkPhoneNumber extends AdaptedPhoneNumber {
public String extension;
public AdaptedWorkPhoneNumber() {
}
public AdaptedWorkPhoneNumber(WorkPhoneNumber workPhoneNumber) {
super(workPhoneNumber);
extension = workPhoneNumber.getExtension();
}
@Override
public WorkPhoneNumber getPhoneNumber() {
WorkPhoneNumber phoneNumber = new WorkPhoneNumber();
phoneNumber.setId(id);
phoneNumber.setNumber(number);
phoneNumber.setExtension(extension);
return phoneNumber;
}
}
@Override
public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception {
AdaptedPhoneNumber adaptedPhoneNumber;
if(phoneNumberList.contains(phoneNumber)) {
if(phoneNumber instanceof WorkPhoneNumber) {
adaptedPhoneNumber = new AdaptedWorkPhoneNumber();
} else {
adaptedPhoneNumber = new AdaptedPhoneNumber();
}
adaptedPhoneNumber.id = phoneNumber.getId();
} else {
if(phoneNumber instanceof WorkPhoneNumber) {
adaptedPhoneNumber = new AdaptedWorkPhoneNumber((WorkPhoneNumber)phoneNumber);
} else {
adaptedPhoneNumber = new AdaptedPhoneNumber(phoneNumber);
}
phoneNumberList.add(phoneNumber);
}
return adaptedPhoneNumber;
}
@Override
public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception {
PhoneNumber phoneNumber = phoneNumberMap.get(adaptedPhoneNumber.id);
if(null != phoneNumber) {
return phoneNumber;
}
phoneNumber = adaptedPhoneNumber.getPhoneNumber();
phoneNumberMap.put(phoneNumber.getId(), phoneNumber);
return phoneNumber;
}
}
Demo
Để đảm bảo cùng một ví dụ của XmlAdapter
được sử dụng cho toàn bộ marshal
và unmarshal
hoạt động chúng tôi đặc biệt phải thiết lập một thể hiện của các XmlAdapter trên cả Marshaller
và Unmarshaller
:
package forum7587095;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setAdapter(new PhoneNumberAdapter());
File xml = new File("src/forum7587095/input.xml");
Customer customer = (Customer) unmarshaller.unmarshal(xml);
System.out.println(customer.getPhoneNumbers().get(0) == customer.getPhoneNumbers().get(2));
System.out.println(customer.getPhoneNumbers().get(3) == customer.getPhoneNumbers().get(4));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setAdapter(new PhoneNumberAdapter());
marshaller.marshal(customer, System.out);
}
}
Đầu ra
true
true
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<phone-number id="A">
<number>555-AAAA</number>
</phone-number>
<phone-number id="B">
<number>555-BBBB</number>
</phone-number>
<phone-number id="A"/>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W">
<number>555-WORK</number>
<extension>1234</extension>
</phone-number>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/>
</customer>
Để biết thêm thông tin
- http://blog.bdoughan.com/2011/09/mixing-nesting-and-references-with.html
- http://blog.bdoughan.com/2010/10/jaxb-and-shared-references-xmlid-and.html
- http://blog.bdoughan.com/search/label/XmlAdapter
- http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html
- http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
Cảm ơn Blaise vì phản hồi rất chi tiết! Khái niệm này có giống nhau không nếu 'PhoneNumber' có các lớp con? Ví dụ, 'Customer' có nhiều tham chiếu đến cùng một cá thể lớp con' PhoneNumber'? – holic87
@ holic87 - Tôi đã cập nhật câu trả lời của mình để 'PhoneNumber' có các lớp con. –
Cảm ơn bạn đã làm rõ! – holic87