Советы и рекомендации по Web-сервисам: Избегайте анонимных типов

Анонимные XML-типы иногда могут быть источником проблем в Web-сервисах. В данной статье рассматриваются эти проблемы и описываются способы, позволяющие их избежать.

Рассел Батек, сертифицированный ИТ-специалист, IBM

Рассел Батек (Russell Butek) работает консультантом по SOA и Web-сервисам IBM. Был одним из разработчиков механизма Web-сервисов WebSphere IBM. Также являлся членом экспертной группы JAX-RPC Java Specification Request (JSR). Принимал участие в реализации механизма Axis SOAP Apache, занимаясь согласованием Axis 1.0 с JAX-RPC.



Шеннон Кендрик, старший ИТ-специалист, IBM

Шеннон Кендрик (Shannon Kendrick) работает старшим ИТ-специалистом в IBM Interactive. В основном занимается разработкой Java EE-приложений для различных клиентов и часто использует Web-сервисы в составе клиентских решений.



14.09.2012

Введение

Мы часто встречаем XML-схемы Web-сервисов, написанные с использованием анонимных типов. Вероятно, авторы не представляют себе потенциальные проблемы, источником которых могут быть подобные схемы. В данной статье классифицируются проблемы, возникающие из-за использования анонимных типов, в надежде на то, что читатели будут их избегать.

Что такое анонимный тип

Анонимный XML-тип – это тип, встроенный в элемент xsd:element и поэтому не имеющий имени. Пример приведен в листинге 1.

Листинг 1. Анонимный тип person
<xsd:element name="person">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="first" type="xsd:string"/>
      <xsd:element name="last" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

Тип complexType в элементе с именем person сам по себе не имеет имени, поэтому является анонимным. Этот анонимный тип можно преобразовать в именованный тип путем выполнения следующих простых действий:

  • Переместите определение complexType в глобальную область видимости.
  • Укажите для complexType атрибут name.
  • Укажите глобальный элемент с атрибутом type, ссылающимся на complexType.

В листинге 2 мы выполнили эти действия и преобразовали анонимный тип в листинге 1 в именованный тип.

Листинг 2. Именованный тип Person
<xsd:element name="person" type="Person"/>
<xsd:complexType name="Person">
  <xsd:sequence>
    <xsd:element name="first" type="xsd:string"/>
    <xsd:element name="last" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

Схемы в листингах 1 и 2 логически идентичны. Любую из них можно использовать для проверки корректности экземпляра XML-кода, приведенного в листинге 3.

Листинг 3. Именованный тип Person
<person>
     <first>John</first>
     <last>Doe</last>
</person>

Чем плохи анонимные типы

В оставшейся части статьи мы будем использовать схемы, приведенные в листингах 4 и 5. В листинге 4 нет ни одного именованного типа. Все типы являются анонимными. Для сравнения в листинге 5 приведена эквивалентная схема с именованными типами. При создании листинга 5 мы применили указанные выше действия к листингу 4.

Листинг 4. Элемент account, определенный с анонимными типами
<xsd:element name="account">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="number" type="xsd:int"/>
      <xsd:element name="person">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="firstName" type="xsd:string"/>
            <xsd:element name="lastName" type="xsd:string"/>
            <xsd:element name="otherNamesOnAccount" minOccurs="0" maxOccurs="unbounded">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element name="person">
                    <xsd:complexType>
                      <xsd:sequence>
                        <xsd:element name="firstName" type="xsd:string"/>
                        <xsd:element name="lastName" type="xsd:string"/>
                      </xsd:sequence>
                    </xsd:complexTypeb>
                  </xsd:element>
                  <xsd:element name="relationshipToAccountOwner" type="xsd:string"/>
                </xsd:sequence>
              </xsd:complexType>
            </xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>
Листинг 5. Элемент account, определенный с именованными типами
<xsd:element name="account" type="tns:Account"/>

<xsd:complexType name="Account">
  <xsd:sequence>
    <xsd:element name="number" type="xsd:int"/>
    <xsd:element name="person" type="tns:AccountOwner"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="AccountOwner">
  <xsd:sequence>
    <xsd:element name="firstName" type="xsd:string"/>
    <xsd:element name="lastName" type="xsd:string"/>
    <xsd:element name="otherNamesOnAccount" minOccurs="0" maxOccurs="unbounded"
        type="tns:OtherNameOnAccount"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="OtherNameOnAccount">
  <xsd:sequence>
    <xsd:element name="person" type="tns:Person"/>
    <xsd:element name="relationshipToAccountOwner" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Person">
  <xsd:sequence>
    <xsd:element name="firstName" type="xsd:string"/>
    <xsd:element name="lastName" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

Почему нам не нравятся анонимные типы в листинге 4?

  • Отсутствует повторное использование.
  • Анонимные типы зачастую все равно нужно именовать.
  • Листинг 4 не так элегантен, как листинг 5.

В оставшейся части статьи мы подробно рассмотрим каждый из этих аспектов.


Отсутствие повторного использования

Это главная проблема анонимных типов. Когда тип определяется анонимно внутри элемента, только этот элемент может иметь данный тип. Если нужно определить еще один элемент того же типа, лучшим вариантом является копирование определения типа в новый элемент.

Например, пара элементов firstName/lastName дублируется в листинге 4 – одна во внешнем элементе person, а вторая во внутреннем элементе person. Чтобы сделать возможным повторное использование, эти два типа следует поместить в их собственный именованный тип. Без такого именованного типа элементы просто копировались бы из одного участка схемы в другой.

Обратите внимание, что в листинге 5 у нас уже есть такой именованный тип – Person. Листинг 5 является именованным эквивалентом листинга 4; мы не сделали ни одного изменения, которое могло бы повлиять на структуру XML-экземпляров. Но теперь, когда у нас есть именованный тип Person, мы сможем улучшить схему в листинге 5, повторно используя тип Person внутри AccountOwner.


Анонимные типы зачастую все равно нужно именовать

Даже если вас не интересует повторное использование, все равно анонимные типы потенциально опасны. Рассмотрим использование XML-схемы. Например, существует достаточно высокая вероятность, что в определении Web-сервиса XML-схема будет отображаться на язык программирования. Если это так, внутри данного языка типы больше не могут быть анонимными. Их нужно как-то назвать, и это имя должно наследоваться из окружающей схемы. Какие бы правила ни использовались для этого, возможен сценарий, нарушающий эти правила.

Например, правила отображения XML-схемы в Java, определенные в спецификации JAXB, нарушаются в схеме, определенной в листинге 4. JAXB определяет, что класс анонимного типа принимает имя, унаследованное от содержащего его элемента. Более того, встроенные анонимные сложные типы в XML становятся внутренними классами в Java. Согласно JAXB, XML-схема, приведенная в листинге 4, будет отображаться в следующие Java-классы:

  • Account
  • Account.Person
  • Account.Person.OtherNamesOnAccount
  • Account.Person.OtherNamesOnAccount.Person

Java не позволяет использовать во вложенных классах одинаковые с содержащими их классами имена. В этом случае будет отображаться следующая ошибка компиляции: "The nested type Person cannot hide an enclosing type".

Мы решаем проблему путем именования всех типов, как это сделано в листинге 5. Можно заметить, что мы применяли главным образом правило наследования имен, описанное в JAXB – наследование имени Java-типа из имени окружающего его элемента. Но мы поступили так не для всех типов, поскольку иначе имели бы два типа Person. Поэтому мы переименовали тип первого элемента Person в AccountOwner.

Файл связывания JAXB

Хотя нам нравится наше решение, оно требует изменения XML-схемы. В тех случаях, когда изменить схему нельзя, JAXB предоставляет другое решение. JAXB позволяет пользователю написать файл связывания (binding file), указывающий механизму JAXB, как отображать XML в Java. Авторы спецификации JAXB знали, что заданное отображение будет работать не всегда, поэтому они предоставили этот механизм отклонения от стандарта. В листинге 6 приведен файл связывания, который указывает генератору JAXB заменить класс, сгенерированный из анонимного типа complexType первого элемента person, на класс с именем AccountOwner.

Листинг 6. Файл связывания JAXB, необходимый для исправления проблемы в листинге 4
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="htp://www.w3.org/2001/XMLSchema-instance" 
mlns:xsd="http://www.w3.org/2001/XMLSchema"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb 
http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
		jaxb:version="2.1">
  <jaxb:bindings schemaLocation="Anonymous.xsd" node="/xsd:schema
    /xsd:element[@name='account']/xsd:complexType/xsd:sequence
    /xsd:element[@name='person']/xsd:complexType">
    <jaxb:class name="AccountOwner"/>
  </jaxb:bindings>
</jaxb:bindings>

Внутренний элемент jaxb:bindings содержит атрибут schemaLocation, указывающий механизму схему, на которую влияет данный файл связывания; он также содержит атрибут node, значение которого представляет собой XPath-выражение для элемента, для которого вы хотите применить специальное связывание. Элемент jaxb:class указывает, что JAXB-класс, сгенерированный из данного элемента XPath, получит имя AccountOwner. Ссылки на дополнительную информацию о файле связывания JAXB приведены в разделе Ресурсы.

Технология JAXB достаточна надежна и позволяет именовать анонимные типы посредством файла связывания. Но это усложняет процесс создания сервиса. Кроме того, нельзя быть уверенным, что все отображения языка предоставят вам такой же уровень функциональности. Поэтому, если возможно, лучше изменять схемы.


Недостаток элегантности

Последняя наша претензия к листингу 4 состоит в том, что он не так элегантен, как листинг 5. Мы допускаем, что это спорный вопрос. Но, по нашему мнению, анонимные типы сложнее читать, чем именованные; XML-структура с большой глубиной вложения почти всегда более трудна для понимания. Структуры анонимных типов труднее анализировать, чем структуры именованных типов.


Заключение

Использования анонимных типов следует избегать по следующим причинам:

  • они не допускают повторного использования;
  • они могут вызывать проблемы, когда отображение должно именовать анонимные типы;
  • они не так элегантны, как именованные типы.

Этих проблем можно избежать, если преобразовать анонимные типы в именованные. Если при JAXB-отображении XML-схем в Java возможность изменения схемы отсутствует, можно создать файл связывания для механизма JAXB, который устранит все возможные проблемы.

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=SOA и web-сервисы
ArticleID=835266
ArticleTitle=Советы и рекомендации по Web-сервисам: Избегайте анонимных типов
publish-date=09142012