Советы и подсказки по Web-сервисам: JAX-RPC против JAX-WS, часть 2 (исходники)

Рассел Бутек, Николас Галлардо

Введение

В то время как некоторые аспекты 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 почти идентичны.

Страница сайта http://185.71.96.61
Оригинал находится по адресу http://185.71.96.61/home.asp?artId=6339