Какой смысл классов JAXB 2 ObjectFactory?

Я новичок в использовании JAXB, и я использовал JAXB 2.1.3 xjc для создания набора классов из моей XML-схемы. В дополнение к генерации класса для каждого элемента в моей схеме он создал класс ObjectFactory.

Кажется, что ничего не мешает мне напрямую создавать элементы, например.

MyElement element = new MyElement();

тогда как учебники, похоже, предпочитают

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

Если я смотрю в ObjectFactory.java, я вижу:

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

так что сделка? Почему я должен даже поддерживать класс ObjectFactory? Я предполагаю, что он также будет перезаписан, если я буду перекомпилировать из измененной схемы.

Ответ 1

Обратная совместимость - не единственная причина.:-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 намного проще. Imaging должен каждый раз писать new JAXBElement вручную!

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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