Почему и когда JAXBElement требуется в JAXB?

Я просто изучаю JAXB (Java Architecture для привязки XML). Прочитав несколько источников, в моем сознании возникло сомнение относительно JAXBElement.

Oracle docs говорят:

When XML element information can not be inferred by the derived Java representation of the XML content, a JAXBElement object is provided. This object has methods for getting and setting the object name and object value. Ссылка здесь

Означает ли это, что JAXBElement необходимо использовать, когда нет прямого сопоставления между определенным типом данных схемы и типом данных Java?

Далее, в одном из примеров кода, перечисленных ниже. который я последовал из здесь:

 ObjectFactory factory = new ObjectFactory();

    UserT user = factory.createUserT();
    user.setUserName("Sanaulla");
    ItemT item = factory.createItemT();
    item.setItemName("Seagate External HDD");
    item.setPurchasedOn("August 24, 2010");
    item.setAmount(new BigDecimal("6776.5"));

    ItemListT itemList = factory.createItemListT();
    itemList.getItem().add(item);

    ExpenseT expense = factory.createExpenseT();// we get expense object here
    expense.setUser(user);
    expense.setItems(itemList);

    JAXBContext context = JAXBContext.newInstance("generated");
    JAXBElement<ExpenseT> element = factory.createExpenseReport(expense);//why is this required
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
    marshaller.marshal(element,System.out);

Используя ExpenseT expense = factory.createExpenseT();, мы можем получить объект ExpenseT.

Снова в коде, если мы видим, мы создаем

JAXBElement<ExpenseT> element = factory.createExpenseReport(expense);
который согласно этому источнику является оберткой для expense object.
С другой стороны, мы не создаем обертки для объектов, извлеченных с помощью
UserT user = factory.createUserT();

Итак, мои вопросы:

  • В чем необходимость JAXBElement оболочки вокруг expense?
  • когда использовать JAXBElement?

Ответ 1

Существует несколько случаев использования JAXBElement:

  • Элемент равен nillable="true" и minOccurs="0". В этом случае, что означает null в отображаемом поле/свойстве? Когда свойство JAXBElement, нулевое значение означает, что элемент отсутствует, а JAXBElement wrapping null означает XML-элемент с xsi:nil="true".
  • Существует два глобальных элемента с одинаковым сложным типом. Поскольку в классах JAXB соответствуют сложным типам, необходим способ, чтобы зафиксировать, какой корневой элемент был встречен.
  • Существует структура выбора, в которой могут встречаться элементы foo или bar, и они являются одним и тем же типом. Здесь требуется JAXBElement, потому что просто встретить значение String недостаточно, чтобы указать, какой элемент должен быть настроен.
  • Элемент с xsi:nil встречается в документе, который содержит атрибуты. В этом примере объект, соответствующий этому элементу, все еще может быть неармаллирован для хранения значений атрибутов, но JAXBElement может указывать, что элемент был нулевым.

Ответ 2

JAXBElement используется для сохранения имени элемента/пространства имен в случаях использования, когда в объектной модели нет достаточной информации. Он часто используется с группами замещения.

Без JAXB metada результат будет завернут в JAXBElement. Вы можете исключить JAXBElement корневого уровня, используя аннотацию @XmlRootElement.

Если вы используете xsd файлы из внешнего источника, и никакая аннотация XmlRootElement не доступна в сгенерированных классах, использование JAXBElement во время процесса сортировки может действительно пригодиться, так как вы можете развязать xml с объектом с помощью оболочки JAXBElement. Вы увидите, что указание самого класса не работает в этом случае...

Это будет работать:

JAXBElement<Object> je = (JAXBElement<Object>) unmarshaller.unmarshal(objectXML);
Object = je.getValue();

Это вызовет исключение JAXBException:

Object obj = (Object) unmarshaller.unmarshal(objectXML);