2012-02-23 12 views
11

Tình hìnhSử dụng JAXB để hỗ trợ schemas với các biến thể nhỏ

tôi cần phải hỗ trợ tạo ra các tài liệu XML dựa trên lược đồ mà thay đổi chỉ hơi giữa mỗi khác. Cụ thể, các lược đồ mà tôi cần hỗ trợ dựa trên các tiêu chuẩn ngành thay đổi đôi chút theo thời gian và các nhà cung cấp có thể tạo phiên bản tùy chỉnh riêng của chúng.

Vấn đề

tôi đã có ý định sử dụng JAXB 2 (từ Metro) với thừa kế như một giải pháp. Tôi mong đợi cấu trúc gói để kết thúc một cái gì đó như thế này:

com.company.xml.schema.v1 
    com.company.xml.schema.v2 
    com.company.xml.schema.v2.vendorxyz 

Trường hợp các lớp trong gói v2 sẽ đơn giản mở rộng các lớp trong gói v1 và ghi đè khi cần thiết. Thật không may, kế hoạch đó đã kết thúc là không thể vì các lớp con không thể ghi đè lên các chú thích trong các lớp cha (see here). Ví dụ, nếu một thuộc tính trong một lược đồ được đổi tên giữa các phiên bản, thì lớp phần tử v2 sẽ phải thực hiện lại hoàn toàn phần tử mà không kế thừa từ v1.

Vì vậy, rằng lá tôi chỉ có hai tùy chọn như xa như tôi có thể nói

Lựa chọn 1

Tạo một "cơ sở" trọn gói cho từng loại lược đồ, chú thích các lớp học phần tử trong gói phần mềm đó với @ XmlAccessorType (XmlAccessType.NONE), và loại bỏ tất cả các chú thích khác. Sau đó, trong mỗi gói được tạo phiên bản, tạo các lớp phân lớp lớp tương ứng trong gói "cơ sở" và thêm tất cả các chú thích bắt buộc. Giải pháp này cho tôi một chút giúp đỡ trong lĩnh vực thừa kế, nhưng sao chép mã là rất lớn và nó sẽ là một thách thức để duy trì.

Lựa chọn 2

Không sử dụng JAXB. Tôi thực sự không thích giải pháp này vì tôi cũng muốn làm việc với JAX-RS/JAX-WS.

Câu hỏi

  • Làm thế nào tôi nên sử dụng JAXB để hỗ trợ nhiều schemas với các biến thể nhỏ, mà không có một loạt các sự trùng lặp mã?
  • Có sự kết hợp công nghệ khác mà tôi nên xem không?

EDIT

Các giải pháp dưới đây từ Blaise làm việc một cách hoàn hảo cho hầu hết các lược đồ của chúng tôi mà chỉ là một bản dịch nhỏ của nhau với chung cùng một dữ liệu. Tuy nhiên, chúng tôi đã gặp phải sự cố trong trường hợp sử dụng thừa kế với tên gói để phiên bản có ý nghĩa hơn. Ví dụ:

com.company.xml.schema.v1.ElementA 
com.company.xml.schema.v2.ElementA 

(nơi v2.ElementA kéo dài v1.ElementA)

Sử dụng OXM MOXY trong trường hợp này tình cờ gặp một lỗi và cách giải quyết có thể được tìm thấy here (với các giải pháp được cung cấp bởi Blaise, không ít hơn!)

Trả lời

5

Lưu ý: Tôi là người lãnh đạo EclipseLink JAXB (MOXy) và là thành viên của nhóm chuyên gia JAXB 2 (JSR-222).

Bạn có thể sử dụng tài liệu ràng buộc bên ngoài trong EclipseLink JAXB để ánh xạ các biến thể giữa các lược đồ XML.

Vendor 1

Bạn có thể sử dụng các chú thích JAXB tiêu chuẩn để lập bản đồ một trong những nhà cung cấp:

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; 
    } 

} 

Vendor 2

Chúng tôi sẽ sử dụng siêu dữ liệu bên ngoài MOXY để tùy chỉnh siêu dữ liệu được cung cấp bởi chú thích. Trong tài liệu (oxm-v2.xml) dưới đây chúng tôi sẽ lập bản đồ firstNamelastName tính đến XML Attributes:

<?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> 

Vendor 3

lần nữa chúng ta sẽ sử dụng bên ngoài tài liệu ràng buộc (oxm-v3.xml) MOXY để ghi đè các chú thích. Lần này chúng ta sẽ tạo thuộc tính id thành phần tử 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-element java-attribute="id" name="identifier"/> 
      </java-attributes> 
     </java-type> 
    </java-types> 
</xml-bindings> 

Demo

Các mẫu mã dưới đây minh chứng để xác định các siêu dữ liệu bên ngoài. Lưu ý cách tôi giới thiệu một nhà cung cấp thứ tư để cho thấy rằng các tài liệu siêu dữ liệu bên ngoài có thể được kết hợp.

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(); 
    } 

} 

Output

Dưới đây là kết quả từ một trong các nhà cung cấp. Hãy nhớ rằng cùng một ví dụ của Customer đã được sử dụng để làm cho mỗi tài liệu XML này.

<?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> 

Để biết thêm thông tin

+1

Cảm ơn bạn rất nhiều vì câu trả lời và các mẫu. Tôi đã chuyển sang triển khai JAXB của MOXy như bạn đã đề xuất và tìm kiếm sự hỗ trợ metatdata bên ngoài rất mạnh mẽ. – Terence

+1

Cảm ơn bạn, điều này đã giúp tôi. Chỉ một điều: kể từ phiên bản 2.4, 'JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY' được thay thế bằng 'JAXBContextProperties.OXM_METADATA_SOURCE'. – DLight

Các vấn đề liên quan