У чому сенс класів ObjectFactory JAXB 2?


98

Я новачок у використанні JAXB, і я використовував xjc JAXB 2.1.3 для створення набору класів зі своєї XML-схеми. Окрім створення класу для кожного елемента моєї схеми, він створив клас ObjectFactory.

Здається, ніщо не заважає мені безпосередньо створити елементи, наприклад

MyElement element = new MyElement();

тоді як навчальні програми, здається, віддають перевагу

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

Якщо я переглядаю ObjectFactory.java, я бачу:

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

так у чому справа? Чому я взагалі мушусь тримати клас ObjectFactory поруч? Я припускаю, що це також буде перезаписано, якщо я буду перекомпілювати з зміненої схеми.


Я не впевнений, чи це призначений дизайн, але я знайшов ObjectFactory ідеальним класом, який слід використовувати для створення JAXBContext. Вам потрібно перерахувати там деякі класи, і JAXB буде слідувати їх методам тощо, тому вони є чимось на зразок коренів. І ObjectFactory має посилання на всі елементи, тому достатньо просто використовувати ObjectFactory.class для створення JAXBContext з усіма відповідними класами.
вбеженар

Відповіді:


68

Зворотна сумісність - не єдина причина. :-P

З більш складними схемами, такими, які мають складні обмеження у значеннях, які може містити вміст елемента, іноді потрібно створити фактичні JAXBElementоб'єкти. Їх зазвичай не банально створювати вручну, тому create*методи роблять важку роботу за вас. Приклад (зі схеми 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);
}

Ось як ви отримуєте <style>тег у <head>тег:

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

Перші три варіанти використання ObjectFactoryможна вважати зайвими (хоч і корисними для консистенції), але четверте робить JAXB набагато простішим у використанні. Уявляючи, що потрібно new JAXBElementкожного разу виписувати вручну!


Чи можете ви навести приклад / довідку про те, яким (або наскільки складним) елементом Schema повинен бути елемент для створення * (), щоб зробити щось корисне? У мене проблеми з пошуком частини схеми, на яку ви посилаєтесь із вашим прикладом JAXB. Якщо пізніше моя схема ускладниться, то, звичайно, було б непогано для create * обробляти її частину для мене, але, оскільки вона є *, навіть не створює
зусиль при

Якщо ви скачаєте тарболи XHTML 1.1 та XHTML Modularization 1.1, ви знайдете каталоги всередині під назвою "SCHEMA". Помістіть усі .xsd файли в ті самі каталоги. Деякі файли .xsd також імпортують w3.org/2001/xml.xsd ; Ви захочете правильно налаштувати розташування, якщо не хочете, щоб файл завантажувався кожного разу під час запуску xjc. [продовження]
Кріс Джестер-Янг

[продовження] Конкретна частина .xsd, яка визначає вміст <head>, у цьому випадку знаходиться в xhtml11-model-1.xsd, у групі xhtml.head.content.
Кріс Єстер-Янг

2
У будь-якому випадку, ніхто не вказує гармати на вашу голову, кажучи, що ви повинні використовувати ObjectFactory (хоча я вважаю, що це зручно використовувати), але коли ви натрапите на випадок, коли він справді корисний, ви це дізнаєтесь. :-)
Кріс Єстер-Янг

Дякую! Я думаю, що моя схема просто недостатньо складна, але я буду пам'ятати про це на майбутнє. :) Я знала, що мені чогось не вистачає.
Ендрю Коулсон,

39

Як зазначав @Chris, іноді JAXB не може працювати з POJO, оскільки схему неможливо точно вказати на Java. У цих випадках JAXBElementоб’єкти обгортки необхідні для надання додаткової інформації про тип.

Є два конкретні приклади, на які я натрапив, де це є загальним.

  • Якщо ви хочете маршалити об'єкт класу, який не має @XmlRootElementанотації. За замовчуванням XJC генерує лише @XmlRootElementдля одних елементів, а не для інших. Точна логіка цього дещо складна, але ви можете змусити XJC генерувати більше @XmlRootElementкласів, використовуючи "простий режим прив'язки"

  • Коли ваша схема використовує групи заміщення. Це досить вдосконалене використання схеми, але XJC перекладає групи замін на Java, активно використовуючи JAXBElementобгортки.

Отже, у створеній XJC об’єктній моделі, яка інтенсивно використовує JAXBElement(з якоїсь причини), вам потрібен спосіб побудови цих JAXBElementекземплярів. Згенерований ObjectFactory- це найпростіший спосіб зробити це. Ви можете побудувати їх самостійно, але це незграбно та схильно до помилок.


Дякуємо за додаткові приклади!
Ендрю Коулсон

2
Нічого собі, це виграшна відповідь. +1
Кріс Єстер-Янг

Мені подобається використовувати анокс для генерування XmlRootElement як 95% часу, якщо у мене є elememtn, який посилається на complexType, я хочу XmlRootElement (ну, більше як 100%, оскільки я не потрапив у випадок використання, коли я не хочу, щоб ще)
Дін Гіллер

9

Зрозуміла зворотна сумісність ...

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

... Більше немає ObjectFactory.createXYZ. Проблема цих заводських методів полягала в тому, що вони кидають перевірену JAXBException. Тепер ви можете просто зробити новий XYZ (), більше немає блоків try / catch. (Я знаю, я знаю, ... це одна з тих речей "про що ми думали !?") ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.