В чем смысл классов 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 со всеми соответствующими классами.
vbezhenar 07

Ответы:

68

Обратная совместимость - не единственная причина. :-П

С более сложными схемами, такими как те, которые имеют сложные ограничения на значения, которые может принимать содержимое элемента, иногда вам нужно создать реальные 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каждый раз писать от руки!

Крис Джестер-Янг
источник
Можете ли вы привести пример / ссылку на то, каким (или насколько сложным) должен быть элемент схемы, чтобы create * () мог делать что-то полезное? Мне сложно найти часть схемы, на которую вы ссылаетесь в своем примере 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 (хотя я считаю его удобным в использовании), но когда вы столкнетесь со случаем, когда это действительно полезно, вы это узнаете. :-)
Chris Jester-Young
Спасибо! Думаю, моя схема недостаточно сложна, но я буду помнить об этом в будущем. :) Я знал, что мне что-то не хватает.
Эндрю Колсон,
39

Как отметил @Chris, иногда JAXB не может работать с POJO, потому что схема не может быть точно отображена на Java. В этих случаях JAXBElementобъекты-оболочки необходимы для предоставления дополнительной информации о типе.

Я встречал два конкретных примера, где это распространено.

  • Если вы хотите маршалировать объект класса, у которого нет @XmlRootElementаннотации. По умолчанию XJC генерирует только @XmlRootElementнекоторые элементы, а не другие. Точная логика для этого немного сложна, но вы можете заставить XJC генерировать больше @XmlRootElementклассов, используя "простой режим привязки".

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

Итак, в объектной модели, созданной XJC, которая интенсивно используется JAXBElement(по какой-либо причине), вам нужен способ создания этих JAXBElementэкземпляров. Сгенерированный ObjectFactory- это, безусловно, самый простой способ сделать это. Вы можете создать их самостоятельно, но это будет неудобно и подвержено ошибкам.

Скаффман
источник
Спасибо за дополнительные примеры!
Эндрю Колсон,
2
Вау, это выигрышный ответ. +1
Крис Джестер-Янг
Мне нравится использовать annox для генерации XmlRootElement в 95% случаев, если у меня есть элемент, который ссылается на complexType, я хочу XmlRootElement (ну, больше как 100%, поскольку я не попал в вариант использования, где я не хочу, чтобы это еще)
Дин Хиллер
9

Думаю, обратная совместимость ...

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

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

Берт Ф
источник