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 во время выполнения.