2011-09-28 15 views
5

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

11

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ộ marshalunmarshal 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ả MarshallerUnmarshaller:

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

+0

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

+1

@ holic87 - Tôi đã cập nhật câu trả lời của mình để 'PhoneNumber' có các lớp con. –

+0

Cảm ơn bạn đã làm rõ! – holic87