Подтвердить что ты не робот

Компилятор 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

4b9b3361

Ответ 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.