Компилятор JAXB связывает xs: boolean с классом оболочки Boolean Java, а не с булевым примитивным типом
Я переношу проект из JAXB 1.0 в JAXB 2.1, и у меня возникают проблемы с отображением типа данных.
Я использую компилятор привязки Ant xjc, и я успешно настроил глобальные привязки, такие как (например) xs: date maps to java.util.Calendar.
Однако я получаю сгенерированные методы, которые возвращают Boolean, и я хочу boolean.
Вот сложный тип:
<xs:element name="usage-auth-rate-charge">
<xs:complexType>
<xs:sequence>
<xs:element name="service-id" type="xs:string"/>
<xs:element name="pricepoint_custom_fields_required" type="xs:boolean" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
И сгенерированный класс выглядит следующим образом:
public class UsageAuthRateCharge {
........
public Boolean isPricepointCustomFieldsRequired() {
return pricepointCustomFieldsRequired;
}
Проблема заключается в том, что, хотя бокс будет работать, если поставляемый XML не содержит значения для pricepoint_custom_fields_required
, класс Boolean field имеет значение null, а не false. Поэтому я получаю NullPointerException, когда делаю что-то вроде этого:
methodWhichTakesPrimitiveBooleanArg(myUsageAuthRateChargeInstance.isPricepointCustomFieldsRequired());
потому что он пытается распаковать Boolean, переданный в - кроме него null.
Я не могу изменить схему, и я не могу настроить весь код клиента для выполнения нулевых проверок.
Я установил атрибут optionalProperty в свой файл binding.xml следующим образом:
<globalBindings optionalProperty="primitive">
В спецификации говорится: "Если значение атрибута" примитивно ", оно связывается, как в JAXB 1.0"
Но это явно не происходит.
Как я могу решить эту проблему?
UPDATE:
Теперь это исправлено в jaxb 2.2.9:
https://java.net/jira/browse/JAXB/fixforversion/16850
Ответы
Ответ 1
Мне стало скучно ждать решения от команды разработчиков, поэтому я свернул рукава и сделал это сам.
Я включаю код ниже, чтобы помочь людям, для которых это тоже проблема.
Отказ от ответственности: мой код, вероятно, не лучший способ решить проблему, но он работает для меня.
Сгенерированный код теперь выглядит следующим образом:
public boolean isPricepointCustomFieldsRequired() {
if (pricepointCustomFieldsRequired == null) {
return false;
} else {
return pricepointCustomFieldsRequired;
}
}
И модификация выглядит следующим образом:
com.sun.tools.xjc.reader.xmlschema.bindinfo.BIProperty: createElementProperty, строка ~ 358
После строки
types.addTo(prop);
введите следующий код:
if (prop.isOptionalPrimitive() && getOptionalPropertyMode() == OptionalPropertyMode.PRIMITIVE &&
!prop.getTypes().isEmpty() && "boolean".equals(prop.getTypes().get(0).getTypeName().getLocalPart()) ) {
prop.defaultValue= CDefaultValue.create(CBuiltinLeafInfo.BOOLEAN, new XmlString("false"));
}
Ответ 2
Проблема
Причина, по которой вы получаете Boolean
вместо Boolean
, заключается в том, что у вас есть minOccurs="0"
в определении элемента. Значение A null
будет сохранено для отсутствующего элемента.
<xs:element name="pricepoint_custom_fields_required" type="xs:boolean" minOccurs="0"/>
Какое решение должно быть
Решение должно быть внешним файлом привязки, который указывает, что примитивный тип должен использоваться для дополнительных значений (см. раздел 7.5.1 спецификации JAXB 2.2).
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings optionalProperty="primitive"/>
</jaxb:bindings>
Внешний файл привязки задается с помощью опции -b
с XJC.
xjc -b binding.xml my-schema.xsd
Почему это решение не работает
Следующие ошибки были обнаружены для отслеживания проблемы с помощью optionalProperty="primitive"
.
Обход
Если вам не нравится способ создания класса в JAXB, вы можете сами создать класс и JAXB вытащить его как часть схемы для генерации класса.
binding.xml
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:bindings schemaLocation="my-schema.xsd">
<jxb:bindings node="//xs:element[@name='usage-auth-rate-charge']/complexType">
<jxb:class ref="com.example.foo.UsageAuthRateCharge"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
UsageAuthRateCharge
Создайте этот класс с помощью тех методов, которые вам нужны.
Вызов XJC
Используйте флаг -b
при вызове XJC, чтобы указать файл binding.xml
xjc -b binding.xml my-schema.xsd
UPDATE
Я действительно надеялся, что один из читателей может быть jaxb dev, который мог легко сменить изменения в jaxb. пользователь archenroot предложил возможное решение в своих комментариях по проблеме jaxb 927 (дубликат 926), что заставляет меня думать, что для права человек, было бы простой задачей исправить jaxb
Я EclipseLink JAXB (MOXy). Я обратился к своим коллегам, которые выполняют эталонную реализацию JAXB (они также работают для Oracle). Ниже приведен ответ, который я получил от них:
Я тестировал в багажнике - и проблема существует. Ill проверить код, как легко это исправить.
Надеюсь, вы сможете получить реальное решение этой проблемы.
Ответ 3
Попробуйте это...
<xs:element name="usage-auth-rate-charge">
<xs:complexType>
<xs:sequence>
<xs:element name="service-id" type="xs:string"/>
</xs:sequence>
<xs:attribute name="chosen" type="xs:boolean" use="required"/>
</xs:complexType>
</xs:element>
Я нашел ваш вопрос, поскольку я смотрел, как делать то же самое, что вы делали. У меня был логический атрибут, который генерировал бы код, который имел бы атрибут как примитивное логическое значение. Чтобы jaxb сгенерировал этот атрибут как логический объект вместо логического примитива, я просто удалил часть использования атрибута use = "required" в xsd.