Điểm của các lớp ObjectFactory của JAXB 2 là gì?


98

Tôi mới sử dụng JAXB và tôi đã sử dụng xjc của JAXB 2.1.3 để tạo một tập hợp các lớp từ Lược đồ XML của mình. Ngoài việc tạo một lớp cho mỗi phần tử trong lược đồ của tôi, nó còn tạo một lớp ObjectFactory.

Dường như không có điều gì ngăn cản tôi khởi tạo trực tiếp các phần tử, ví dụ:

MyElement element = new MyElement();

trong khi hướng dẫn có vẻ thích

MyElement element = new ObjectFactory().createMyElement();

Nếu tôi nhìn vào ObjectFactory.java, tôi thấy:

public MyElement createMyElement() {
    return new MyElement();
}

Vậy thỏa thuận là gì? Tại sao tôi phải bận tâm giữ lớp ObjectFactory xung quanh? Tôi cho rằng nó cũng sẽ bị ghi đè nếu tôi biên dịch lại từ một lược đồ đã thay đổi.


Tôi không chắc đó có phải là thiết kế dự định hay không, nhưng tôi thấy ObjectFactory là một lớp lý tưởng để sử dụng cho việc tạo JAXBContext. Bạn cần liệt kê một số lớp ở đó và JAXB sẽ tuân theo các phương thức của chúng, v.v., vì vậy chúng giống như root. Và ObjectFactory có tham chiếu đến tất cả các phần tử, vì vậy chỉ cần sử dụng ObjectFactory.class để tạo JAXBContext với tất cả các lớp có liên quan là đủ.
vbezhenar

Câu trả lời:


68

Khả năng tương thích ngược không phải là lý do duy nhất. :-P

Với các lược đồ phức tạp hơn, chẳng hạn như các lược đồ có ràng buộc phức tạp đối với các giá trị mà nội dung của phần tử có thể đảm nhận, đôi khi bạn cần tạo JAXBElementcác đối tượng thực tế . Chúng thường không nhỏ để tạo ra bằng tay, vì vậy các create*phương pháp này thực hiện công việc khó khăn cho bạn. Ví dụ (từ lược đồ XHTML 1.1):

@XmlElementDecl(namespace = "http://www.w3.org/1999/xhtml", name = "style", scope = XhtmlHeadType.class)
public JAXBElement<XhtmlStyleType> createXhtmlHeadTypeStyle(XhtmlStyleType value) {
    return new JAXBElement<XhtmlStyleType>(_XhtmlHeadTypeStyle_QNAME, XhtmlStyleType.class, XhtmlHeadType.class, value);
}

Đây là cách bạn lấy <style>thẻ vào <head>thẻ:

ObjectFactory factory = new ObjectFactory();
XhtmlHtmlType html = factory.createXhtmlHtmlType();
XhtmlHeadType head = factory.createXhtmlHeadType();
html.setHead(head);
XhtmlStyleType style = factory.createXhtmlStyleType();
head.getContent().add(factory.createXhtmlHeadTypeStyle(style));

Ba cách sử dụng đầu tiên ObjectFactorycó thể được coi là thừa (mặc dù hữu ích cho tính nhất quán), nhưng cách sử dụng thứ tư làm cho JAXB dễ sử dụng hơn rất nhiều. Hình ảnh phải viết new JAXBElementra bằng tay mỗi lần!


Bạn có thể đưa ra một ví dụ / tham chiếu về những gì (hoặc mức độ phức tạp) mà một phần tử Schema cần phải có để tạo * () làm điều gì đó hữu ích không? Tôi đang gặp sự cố khi tìm phần của Lược đồ mà bạn đang tham chiếu với ví dụ JAXB của mình. Nếu sau này Lược đồ của tôi phức tạp hơn, chắc chắn sẽ rất tốt cho việc tạo * xử lý một phần của nó cho tôi, nhưng vì nó là việc tạo * thậm chí không bận tâm đến việc tự tạo các phần tử phụ ..
Andrew Coleson

Nếu bạn tải xuống các tarball XHTML 1.1 và XHTML Modulization 1.1, bạn sẽ thấy các thư mục bên trong được gọi là "SCHEMA". Đặt tất cả các tệp .xsd trong cùng một thư mục. Một số tệp .xsd cũng sẽ nhập w3.org/2001/xml.xsd ; bạn sẽ muốn điều chỉnh các vị trí một cách thích hợp nếu bạn không muốn tệp được tải xuống mỗi khi bạn chạy xjc. [tt]
Chris Jester-Young

[tt] Phần cụ thể của .xsd chỉ định nội dung của <head>, trong trường hợp này, trong xhtml11-model-1.xsd, thuộc nhóm xhtml.head.content.
Chris Jester-Young

2
Trong mọi trường hợp, không ai chĩa súng vào đầu bạn nói rằng bạn phải sử dụng ObjectFactory (mặc dù tôi thấy nó rất tiện để sử dụng), nhưng khi bạn gặp trường hợp nó thực sự hữu ích, bạn sẽ biết nó. :-)
Chris Jester-Young

Cảm ơn! Tôi đoán giản đồ của tôi không đủ phức tạp, nhưng tôi sẽ ghi nhớ nó cho tương lai. :) Tôi biết tôi phải thiếu một cái gì đó.
Andrew Coleson

39

Như @Chris đã chỉ ra, đôi khi JAXB không thể hoạt động với POJO, vì lược đồ không thể được ánh xạ chính xác vào Java. Trong những trường hợp này, JAXBElementcác đối tượng trình bao bọc là cần thiết để cung cấp thông tin loại bổ sung.

Có hai ví dụ cụ thể mà tôi đã gặp ở nơi điều này phổ biến.

  • Nếu bạn muốn điều chỉnh một đối tượng của một lớp không có @XmlRootElementchú thích. Theo mặc định, XJC chỉ tạo @XmlRootElementcho một số phần tử và không tạo cho những phần tử khác. Logic chính xác cho điều này hơi phức tạp, nhưng bạn có thể buộc XJC tạo nhiều @XmlRootElementlớp hơn bằng cách sử dụng "chế độ liên kết đơn giản"

  • Khi lược đồ của bạn sử dụng các nhóm thay thế. Đây là cách sử dụng lược đồ khá nâng cao, nhưng XJC chuyển các nhóm thay thế sang Java bằng cách sử dụng nhiều JAXBElementtrình bao bọc.

Vì vậy, trong một mô hình đối tượng do XJC tạo ra sử dụng nhiều JAXBElement(vì bất kỳ lý do gì), bạn cần một cách để xây dựng các JAXBElementthể hiện đó. Tạo ra ObjectFactorycho đến nay là cách dễ nhất để làm điều đó. Bạn có thể tự mình xây dựng chúng, nhưng làm như vậy sẽ rất khó và dễ xảy ra lỗi.


Cảm ơn các ví dụ bổ sung!
Andrew Coleson, 02/09/09

2
Wow, đó là một câu trả lời chiến thắng. +1
Chris Jester-Young

Tôi thích sử dụng securex để tạo XmlRootElement là 95% thời gian nếu tôi có elememtn đề cập đến một loại complexType, tôi muốn XmlRootElement (tốt, giống như 100% vì tôi đã không gặp trường hợp sử dụng mà tôi không muốn điều đó chưa)
Dean Hiller

9

Khả năng tương thích ngược, tôi đoán ...

http://weblogs.java.net/blog/kohsuke/archive/2005/08/a_story_of_migr.html :

... Không còn ObjectFactory.createXYZ. Vấn đề với các phương thức gốc đó là chúng ném một JAXBException đã được kiểm tra. Bây giờ bạn có thể chỉ cần thực hiện XYZ () mới, không cần thử / bắt khối nữa. (Tôi biết, tôi biết, ... đây là một trong những thứ "chúng ta đang nghĩ gì !?") ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.