Рассел Бутек, Николас Галлардо
Введение
В то время как некоторые аспекты JAX-WS 2.0 в JAX-RPC 1.1 просто претерпели эволюцию, другие изменились самым революционным образом. Например, JAX-WS не поддерживает сопоставление данных между XML schema и Java, что является главной функцией в JAX-RPC 1.1. Вместо этого в JAX-WS для такого сопоставления используется другая JCP-технология, JAXB 2.0 (Java Architecture for XML Binding, Java-архитектура для описания привязки для XML-данных) . JAX-WS просто представляет модель вызова для Web-сервисов. Данную спецификацию больше не интересуют bean-компоненты Java, представляющие данные приложения; она концентрируется только на поставке этих данных Web-сервису назначения. В этой статье мы сравниваем сопоставления в JAX-RPC 1.1 и JAXB 2.0.
Сопоставления XML schema - Java
|
JAX-RPC и JAXB Почему с самого начала JAX-RPC не использует JAXB? Ответ кроется в расхождении данных разработок во времени. Первая версия JAX-RPC была закончена раньше JAXB, поэтому разработчики JAX-RPC решили не ждать и разработали свою функцию сопоставления имен. | |
Методы сопоставления имен XML именам Java в JAX-RPC и JAX-WS/JAXB в основном аналогичны, хотя сопоставление примитивных типов в них слегка отличается. В таблице 1 перечислены эти различия; они могут показаться существенными; однако, если не считать типов для даты/времени, это наименее используемые примитивные типы данных XML.
Таблица 1. Различия в сопоставлении данных между JAX-RPC 1.1 и JAXB 2.0 для примитивных типов XML
Тип |
JAX-RPC 1.1 |
JAXB 2.0 |
xsd:anySimpleType |
java.lang.String |
java.lang.Object |
xsd:duration |
java.lang.String |
javax.xml.datatype.Duration (новый тип) |
xsd:dateTime |
java.util.Calendar |
javax.xml.datatype.XMLGregorianCalendar (новый тип) |
xsd:time |
java.util.Calendar |
javax.xml.datatype.XMLGregorianCalendar |
xsd:date |
java.util.Calendar |
javax.xml.datatype.XMLGregorianCalendar |
xsd:gYearMonth |
java.lang.String |
javax.xml.datatype.XMLGregorianCalendar |
xsd:gYear |
java.lang.String |
javax.xml.datatype.XMLGregorianCalendar |
xsd:gMonthDay |
java.lang.String |
javax.xml.datatype.XMLGregorianCalendar |
xsd:gMonth |
java.lang.String |
javax.xml.datatype.XMLGregorianCalendar |
xsd:gDay |
java.lang.String |
javax.xml.datatype.XMLGregorianCalendar |
xsd:anyURI |
java.net.URI |
java.lang.String |
xsd:NMTOKENS |
java.lang.String[] |
java.util.List<java.lang.String> |
xsd:IDREF |
java.lang.String |
java.lang.Object |
xsd:IDREFS |
java.lang.String[] |
java.util.List<java.lang.Object> |
xsd:ENTITY |
не поддерживается |
java.lang.String |
xsd:ENTITIES |
не поддерживается |
java.util.List<java.lang.String> |
Аспекты "pure Java" для сопоставлений примитивных типов данных почти не отличаются в JAX-RPC и JAXB, но сопоставления в JAXB, помимо этого, используют новую функцию аннотаций Java. В листингах с 1 по 3 приводится несколько примеров сопоставлений примитивных типов данных.
Листинг 1. Элементы и атрибуты XML-типа complexType
<xsd:sequence>
<xsd:element name="intField" type="xsd:int"/>
<xsd:element name="intMinField" type="xsd:int" minOccurs="0"/>
<xsd:element name="intNilField" type="xsd:int" nillable="true"/>
<xsd:element name="stringField" type="xsd:string"/>
<xsd:element name="stringMinField" type="xsd:string" minOccurs="0"/>
<xsd:element name="stringNilField" type="xsd:string" nillable="true"/>
</xsd:sequence>
<xsd:attribute name="intAttr" type="xsd:int"/>
<xsd:attribute name="intAttrReq" type="xsd:int" use="required"/>
|
Листинг 2. Сопоставление в свойствах bean-компонентов Java по JAX-RPC 1.1
private int intField;
private Integer intMinField;
private Integer intNilField;
private String stringField;
private String stringMinField;
private String stringNilField;
private Integer intAtt;
private int intAttReq;
|
Листинг 3. Сопоставление в свойствах bean-компонентов Java по JAXB 2.0
protected int intField;
protected Integer intMinField;
@XmlElement(required = true, type = Integer.class, nillable = true)
protected Integer intNilField;
@XmlElement(required = true)
protected String stringField;
protected String stringMinField;
@XmlElement(required = true, nillable = true)
protected String stringNilField;
@XmlAttribute
protected Integer intAtt;
@XmlAttribute(required = true)
protected int intAttReq;
|
В bean-компоненте, сгенерированном в JAX-RPC 1.1, вы не сможете определить разницу между:
- Полем элемента и полем атрибута;
- Полем, преобразованным в результате сопоставления из
minOccurs="0" type="xsd:int"
, и полем, преобразованным из nillable="true" type="xsd:int"
;
- Полями, преобразованными в результате сопоставления из
type="xsd:string"
и type="xsd:string" minOccurs="0"
.
Но теперь это можно сделать благодаря тому, что JAXB использует новые аннотации Java. Аннотации @XmlElement
и @XmlAttribute
имеют несколько параметров. Ниже перечислены те из них, которые имеют отношение к теме данной статьи:
- Required: Должен ли существовать этот элемент? Например, может ли
minOccurs
принимать другие значения помимо 1?
- Nillable: Содержит ли поле атрибут
nillable="true"
?
Сопоставление массивов
Сопоставление массивов XML в Java в моделях JAX-RPC и JAXB различно, потому что JAXB использует новую родовую функцию Java, как показано в листингах 4-6.
Листинг 4. XML-массив
<xsd:element name="intArrayField" type="xsd:int" minOccurs="0" maxOccurs="unbounded"/>
|
Листинг 5. Сопоставление в свойствах Java Bean по JAX-RPC 1.1
private int[] intArrayField;
public int[] getIntArrayField() {..}
public void setIntArrayField(int[] intArrayField) {..}
public int getIntArrayField(int i) {..}
public void setIntArrayField(int i, int value) {..}
|
Листинг 6. Сопоставление в свойствах Java Bean по JAXB 2.0
@XmlElement(type = Integer.class)
protected List<Integer> intArrayField;
public List<Integer> getIntArrayField() {..}
|
Обратите внимание на различия в методах доступа. Сопоставление в JAX-RPC следует строгому определению методов доступа к массиву bean-компонента Java. Сопоставление в JAXB не отображает данные в массив, поэтому оно несколько отличается. Метод getIntArrayField
возвращает в активный список не только моментальный снимок, но и ссылку. Следовательно, любое изменение, которое вы внесете в возвращаемый список, будет представлено в рамках свойства. Именно поэтому для свойств массива не существует метод set
.
Отображение составных типов
Сопоставление complexType
почти не отличается в JAX-RPC и JAXB, за исключением полей с атрибутом " private" в JAX-RPC и "protected" в JAXB, а сопоставление JAXB добавляет аннотации, описывающие порядок сортировки в поле. В листингах 7-9 приведены пример и сравнение этих двух сопоставлений.
Листинг 7. XML-схема: тип complexType
<xsd:element name="Phone" type="tns:Phone"/>
<xsd:complexType name="Phone">
<xsd:sequence>
<xsd:element name="areaCode" type="xsd:string"/>
<xsd:element name="exchange" type="xsd:string"/>
<xsd:element name="number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
|
Листинг 8. Сопоставление complexType в JAX-RPC 1.1
public class Phone {
private String areaCode;
private String exchange;
private String number;
..
} |
Листинг 9. Сопоставление complexType в JAXB 2.0
@XmlType(name = "Phone", propOrder = {
"areaCode",
"exchange",
"number"
})
public class Phone {
@XmlElement(required = true)
protected String areaCode;
@XmlElement(required = true)
protected String exchange;
@XmlElement(required = true)
protected String number;
..
} |
Обратите внимание на то, что в схеме из листинга 7 используется xsd:sequence
. Если бы вместо этого стояло xsd:all
, то комментарий propOrder
был бы пустым: @XmlType(name = "Phone", propOrder = {})
.
Новый класс ObjectFactory
JAXB генерирует один файл, который отсутствует в JAX-RPC: ObjectFactory
. Каждый каталог, содержащий bean-компоненты Java, будет включать один файл ObjectFactory
. Для каждого типа, определенного в пространстве имен, соответствующем данной схеме, класс ObjectFactory
будет иметь метод create. Для каждого элемента класс ObjectFactory
будет иметь метод create element, возвращающий экземпляр javax.xml.bind.JAXBElement<Type>
. Например, в листинге 10 показан класс ObjectFactory
, сгенерированный для схемы Phone из листинга 7 с методом, возвращающим экземпляр Phone
, и методом, возвращающим экземпляр JAXBElement<Phone>
. По-прежнему допускается создание экземпляров bean-компонентов в этом каталоге, но лучше воспользоваться фабрикой.
Листинг 10. ObjectFactory JAXB 2.0 для Phone
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.namespace.QName;
public class ObjectFactory {
private final static QName _Phone_QNAME = new QName
("urn:types.MyServiceSample.ibm.com", "Phone");
public ObjectFactory() {..}
public Phone createPhone() {..}
@XmlElementDecl(namespace = "urn:types.MyServiceSample.ibm.com", name = "Phone")
public JAXBElement<Phone> createPhone(Phone value) {..}
}
|
Сопоставления Java - XML schema
Благодаря рациональной вставке описанных выше новых определенных в JAXB-аннотаций, можно точно сопоставить Java и XML, особенно в направлении, обратном сопоставлению XML-Java, о котором мы говорили. А как быть с Java без аннотаций?
Сопоставления имен в Java именам в XML по спецификациям JAX-RPC и JAXB, в основном, аналогичны. То есть, примитивные типы Java сопоставляются таким же типам XML schema, независимо от того, используется ли сопоставление по модели JAX-RPC или по модели JAXB. Спецификация JAX-RPC определяет небольшой набор стандартных классов Java, сопоставляемых XML. Сопоставления всех классов, кроме одного, в JAXB практически одинаково, но при этом JAXB добавляет еще несколько сопоставимых классов, как показано в таблице 2.
Таблица 2. Различия в сопоставлении данных между JAX-RPC 1.1 и JAXB 2.0 для стандартных классов Java
Тип |
JAX-RPC 1.1 |
JAXB 2.0 |
java.lang.String |
xsd:string |
xsd:string |
java.math.BigInteger |
xsd:integer |
xsd:integer |
java.math.BigDecimal |
xsd:decimal |
xsd:decimal |
java.util.Calendar |
xsd:dateTime |
xsd:dateTime |
java.util.Date |
xsd:dateTime |
xsd:dateTime |
javax.xml.namespace.QName |
xsd:QName |
xsd:QName |
java.net.URI |
xsd:anyURI |
xsd:string |
javax.xml.datatype.XMLGregorianCalendar |
нет |
xsd:anySimpleType |
javax.xml.datatype.Duration |
нет |
xsd:duration |
java.lang.Object |
нет1 |
xsd:anyType |
java.awt.Image |
нет2 |
xsd:base64Binary |
javax.activation.DataHandler |
нет2 |
xsd:base64Binary |
javax.xml.transform.Source |
нет2 |
xsd:base64Binary |
java.util.UUID |
нет |
xsd:string |
Примечания к таблице 2:
1. Некоторые производители сопоставляют класс java.lang.Object классу xsd:anyType.
2. В JAX-RPC этот класс сопоставляется типу mime binding - тип XML не определен.
Заключение
Мы сравнили сопоставления в JAX-RPC 1.1 и JAXB 2.0. В целом, они аналогичны, за небольшими исключениями:
- XML - Java:
- Есть отличия в сопоставлении небольшой части примитивных типов;
- В JAXB добавлен класс ObjectFactory;
- В JAXB используются новая функция аннотирования и новая родовая функция языка Java.
- Java - XML:
- Сопоставления примитивных типов идентичны;
- Сопоставления стандартных классов Java почти идентичны.