JAXB избегать JAXBElement<?>
Я хочу генерировать классы Java с JAXB из файла XSD.
Проблема в том, что я всегда получаю несколько классов, подобных этому (пространство имен удалено):
public static class Action {
@XmlElementRefs({
@XmlElementRef(name = "ReportStateCanceled", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "ReportDate", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "ReportStatePreliminary", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "DocumentID", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "ReportStateNotValidated", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "CaseNo", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "PatientID", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "DocumentKey", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "ReportTime", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "ReportHeading", namespace = "http://...", type = JAXBElement.class, required = false),
@XmlElementRef(name = "ReportStateComplete", namespace = "http://...", type = JAXBElement.class, required = false)
})
protected List<JAXBElement<?>> documentKeyOrDocumentIDOrPatientID;
@XmlAttribute(name = "name")
protected String name;
@XmlAttribute(name = "Query")
protected String query;
/**
* Gets the value of the documentKeyOrDocumentIDOrPatientID property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the documentKeyOrDocumentIDOrPatientID property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getDocumentKeyOrDocumentIDOrPatientID().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link JAXBElement }{@code <}{@link Template.Page.Actions.Action.ReportDate }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
* {@link JAXBElement }{@code <}{@link Template.Page.Actions.Action.ReportTime }{@code >}
* {@link JAXBElement }{@code <}{@link String }{@code >}
*
*
*/
public List<JAXBElement<?>> getDocumentKeyOrDocumentIDOrPatientID() {
if (documentKeyOrDocumentIDOrPatientID == null) {
documentKeyOrDocumentIDOrPatientID = new ArrayList<JAXBElement<?>>();
}
return this.documentKeyOrDocumentIDOrPatientID;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the query property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getQuery() {
return query;
}
/**
* Sets the value of the query property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setQuery(String value) {
this.query = value;
}
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <simpleContent>
* <extension base="<http://www.w3.org/2001/XMLSchema>string">
* <attribute name="dateFormat" type="{http://www.w3.org/2001/XMLSchema}string" />
* </extension>
* </simpleContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"value"
})
public static class ReportDate {
@XmlValue
protected String value;
@XmlAttribute(name = "dateFormat")
protected String dateFormat;
/**
* Gets the value of the value property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setValue(String value) {
this.value = value;
}
/**
* Gets the value of the dateFormat property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getDateFormat() {
return dateFormat;
}
/**
* Sets the value of the dateFormat property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setDateFormat(String value) {
this.dateFormat = value;
}
}
Как вы можете видеть, JAXB использует JAXBElement. Такие занятия для меня непригодны.
После некоторых исследований я обнаружил, что у JAXB есть проблемы с nillable="true"
а также minOccurs="0"
вместе, но я нигде не пользуюсь nillable. Хотя я уверен, что проблема связана с minOccurs
а также maxOccurs
,
Даже если бы я знал точную проблему, это была бы проблема, потому что я получаю XSD от внешнего человека, и мне не разрешено изменять его.
Фрагмент XSD:
<xs:element name="Action" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="DocumentKey" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="DocumentID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="PatientID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="CaseNo" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportHeading" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportDate" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string" >
<xs:attribute name="dateFormat" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="ReportTime" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string" >
<xs:attribute name="timeFormat" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="ReportStateNotValidated" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportStatePreliminary" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportStateComplete" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportStateCanceled" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:choice>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="Query" type="xs:string" />
</xs:complexType>
</xs:element>
Поэтому я искал другое решение. Я всегда приходил к выводу, что могу решить эту проблему, если добавлю jaxb-binding.xml при создании классов из XSD.
Я попробовал некоторые привязки, но это никогда не работало.
С этим связыванием я получаю меньше JAXBElements, но я получаю интерфейсы вместо классов.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
jaxb:version="2.0">
<xs:annotation>
<xs:appinfo>
<jaxb:globalBindings generateValueClass="false" generateElementProperty="false" >
<xjc:simple />
</jaxb:globalBindings>
</xs:appinfo>
</xs:annotation>
</xs:schema>
А теперь я спрашиваю, знает ли кто-нибудь решение? Лучшее решение было бы, если бы кто-нибудь предоставил мне работающий jaxb-binding.xml.
Я использую версию 2.2.4-2 компилятора xjc.
Заранее спасибо!
2 ответа
Эта проблема
Проблема в том, что ваш xs:choice
элемент имеет maxOccurs="unbounded"
,
<xs:choice minOccurs="0" maxOccurs="unbounded">
JAXB Spec Ссылка
Из-за этого JAXB не может генерировать отдельные свойства для каждого параметра в структуре выбора. См. "6.12.6 Связывание повторяющейся группы моделей вхождений" спецификации JAXB 2.2 (JSR-222) для получения более подробной информации:
Почему это проблема
Следующий фрагмент XML действителен в соответствии с вашей схемой XML и должен иметь возможность быть представленным в сгенерированной объектной модели.
<Action>
<DocumentID/>
<PatientID/>
<PatientID/>
<DocumentID/>
</Action>
Работа вокруг
Если вам действительно не нравится класс, который генерирует JAXB, вы можете создать свой собственный и указать через файл привязок, что JAXB должен использовать его вместо создания нового.
<jxb:bindings schemaLocation="yourSchema.xsd">
<jxb:bindings node="//xs:element[@name='Action']">
<jxb:class ref="com.example.Action"/>
</jxb:bindings>
</jxb:bindings>
Я написал плагин Simpify именно для этой проблемы.
<xs:schema ...
xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify"
jaxb:extensionBindingPrefixes="... simplify">
<xs:complexType name="typeWithReferencesProperty">
<xs:choice maxOccurs="unbounded">
<xs:element name="a" type="someType">
<xs:annotation>
<xs:appinfo>
<simplify:as-element-property/>
</xs:appinfo>
</xs:annotation>
</xs:element>
<xs:element name="b" type="someType"/>
</xs:choice>
</xs:complexType>
дам тебе
@XmlElement(name = "a")
protected List<SomeType> a;
@XmlElement(name = "b")
protected List<SomeType> b;
вместо
@XmlElementRefs({
@XmlElementRef(name = "a", type = JAXBElement.class),
@XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;
Отказ от ответственности: я автор.