JAXB генерирует нежелательные @XMLValue

Я уже почти пол недели пытаюсь решить проблему, и мне нужна помощь, потому что я не могу добиться успеха.

Я унаследовал приложение, которое 8 лет не обрабатывалось... все еще на Java 1.4, сборке Maven1, новых модульных тестов 8 лет не было...

В настоящее время обновление до Java 1.6 (ветвь Java 1.8 также выполняется параллельно, будет тестироваться и то и другое), а Maven 3.3.3 успешно работает - добились отличных успехов.

Теперь я врезался в стену и некоторое время не совершал прорыв.

Старые источники использовали локальные JAXB 1.3 jar для генерации классов из большого XSD.

Мне пришлось перейти с JAXB1.3 на JAXB2.1 - что также означало, что мне пришлось потратить много времени на переписывание всех ссылок на сгенерированные классы по мере изменения соглашений об именах. В любом случае, много времени было потрачено на то, чтобы компилировать код.

Наконец, он компилируется, и я пробую модульный тест, чтобы увидеть, как он работает. Это где я ударил свою проблему.

Большинство скомпилированных классов работают нормально, но три пакета выдают исключения, когда я пытаюсь сгенерировать JAXBContext:

@XmlValue не допускается для класса, который наследует другой класс.

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

    <xs:element name="ContactName">
    <xs:complexType>
        <xs:simpleContent>
            <xs:extension base="xs:string">
                <xs:attribute name="First" type="xs:string"/>
                <xs:attribute name="Middle" type="xs:string"/>
                <xs:attribute name="Last" type="xs:string"/>
                <xs:attribute name="Name" type="xs:string"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>
</xs:element>

и затем на этот элемент ссылаются в другом следующим образом:

<xs:element name="ContactInfo">
    <xs:complexType>
        <xs:annotation>
            <xs:documentation>Common contact information</xs:documentation>
        </xs:annotation>
        <xs:sequence>
            <xs:element ref="ContactName" minOccurs="0" maxOccurs="unbounded"/>
            <xs:element ref="ContactID" minOccurs="0"/>
            <xs:element ref="ContactDivision" minOccurs="0" maxOccurs="unbounded"/>
            .....

это генерируется в:

Контактное лицо:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "value"
})
@XmlRootElement(name = "ContactName")
public class ContactName
    extends BaseJaxbDoc
    implements Serializable, Cloneable, CopyTo
{

    private final static long serialVersionUID = 47110815L;
    @XmlValue
    protected String value;
    @XmlAttribute(name = "First")
    protected String first;
    @XmlAttribute(name = "Middle")
    protected String middle;
    @XmlAttribute(name = "Last")
    protected String last;
    @XmlAttribute(name = "Name")
    protected String name;

И затем объявлено в ContactInfo следующим образом:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "contactName",
    "contactID",
    "contactDivision",
    "contactPhone",
    "contactPhoneHome",
    "contactPhoneMobile",
    "contactFax",
    "contactEmail",
    "contactEmail2"
})
@XmlRootElement(name = "ContactInfo")
public class ContactInfo
    extends BaseJaxbDoc
    implements Serializable, Cloneable, CopyTo
{

    private final static long serialVersionUID = 47110815L;
    @XmlElement(name = "ContactName")
    protected List<ContactName> contactName;

Исключение составляет:

this problem is related to the following location:
    at protected java.lang.String xxx.xx.xxxx.xxxx.orders.jaxb.ContactName.value
    at xxx.xx.xxxx.xxxx.orders.jaxb.ContactName
    at protected java.util.List xxx.xx.xxxx.xxxx.orders.jaxb.ContactInfo.contactName
    at xxx.xx.xxxx.xxxx.orders.jaxb.ContactInfo
    at protected java.util.List xxx.xx.xxxx.xxxx.orders.jaxb.CustomerReference.contactInfo
    at xxx.xx.xxxx.xxxx.orders.jaxb.CustomerReference
    at protected java.util.List xxx.xx.xxxx.xxxx.orders.jaxb.Item.customerReference
    at xxx.xx.xxxx.xxxx.orders.jaxb.Item
    at public xxx.xx.xxxx.xxxx.orders.jaxb.Item xxx.xx.xxxx.xxxx.orders.jaxb.ObjectFactory.createItem()
    at xxx.xx.xxxx.xxxx.orders.jaxb.ObjectFactory

В исходной схеме есть XML-преобразование, удаляющее комментарии и создающее типы jaxb:typesafeEnum. Затем преобразованная схема используется с файлом привязки jxb для привязки всего к внутреннему суперклассу jaxb helper - BaseJaxbDoc

        <jaxb:globalBindings generateIsSetMethod="true">
        <xjc:serializable uid="47110815"/>
        <xjc:superClass name="xxx.xx.xxxx.xxxx.helpers.BaseJaxbDoc"/>
        <jaxb:javaType name="java.math.BigDecimal" xmlType="xs:decimal" 
             parseMethod="xxx.xx.xxxx.xxxx.helpers.AmountConverter.parseAmount" 
            printMethod="xxx.xx.xxxx.xxxx.helpers.AmountConverter.printAmount"/>
        </jaxb:globalBindings>

Это потому, что я использую xjc на 9 различных схемах, все они генерируют пакеты классов JAXB.

Все классы имеют один и тот же суперкласс (определенный в файле привязок для каждой схемы) для реализации классов JAXB marshall/unmarshall только один раз вместе с некоторыми другими вспомогательными функциями. Итак, мой вопрос, как обойти это исключение, когда я не могу изменить схему? Что-то в XSLT или что-то в файле bindings?

Мои зависимости Maven: для JAXB: org.jvnet.jaxb2.maven2 maven-jaxb21-plugin 0.13.0

JAXB runtime: org.glassfish.jaxb jaxb-runtime 2.2.11

1 ответ

Решение

Попробуйте аннотировать BaseJaxbDoc с @XmlTransient,

Проблема, которую вы получаете, производится здесь:

                if(getBaseClass()!=null) {
                    builder.reportError(new IllegalAnnotationException(
                        Messages.XMLVALUE_IN_DERIVED_TYPE.format(), p ));
                }

JAXB думает, что ваш BaseJaxbDoc это базовый класс. Так что вы должны либо удалить xjc:superClass или заставьте JAXB думать, что у вашего класса нет базового класса.

Когда я смотрю на эту часть кода в ModelBuilder:

        if(reader.hasClassAnnotation(clazz,XmlTransient.class) || isReplaced) {
            // handle it as if the base class was specified
            r = getClassInfo( nav.getSuperClass(clazz), searchForSuperClass,
                    new ClassLocatable<C>(upstream,clazz,nav) );
        }

Кажется, что ModelBuilder признает @XmlTransient на занятиях и не считает их. Так что есть шанс, что задница @XmlTransient на ваше BaseJaxbDoc помог бы.

Другой вариант - сбросить BaseJaxbDoc построить. Вы используете наследование классов для добавления функций маршала / демаршала к классам, производным от схемы. Я бы предпочел перенести эту функциональность в некоторые внешние сервисы. Это, вероятно, не вариант здесь, поскольку вы, вероятно, сталкиваетесь с большим количеством устаревшего кода.

Еще один вариант - попробовать MOXy вместо JAXB RI во время выполнения.

Другие вопросы по тегам