IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  SOA и Web-сервисы | XML | Технология Java  >

Советы по программированию Web-сервисов: Улучшение функциональной совместимости J2EE и .NET, Часть 2

Управление коллекциями, массивами и примитивами

developerWorks
Опции документа

Опции документа, требующие включения JavaScript, не отображаются


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Wangming Ye, Инженер-программист, IBM

21.01.2005

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

Введение

В предыдущей части обсуждалась важность проектирования Языка Описания Web-сервисов - Web Services Description Language (WSDL) и типов данных XML Schema (XSD) перед написанием кода. В ней также мы обсуждали основную причину использования стиля Document/literal и необходимость проверки согласования базового профиля WS-I (WS-I Basic Profile) при разработке Web-сервисов. Сегодня мы проиллюстрируем использование типов данных и их воздействие на функциональную совместимость.

Входящие параметры и результирующие значения типов данных Web-сервиса имеют большое влияние на его функциональную совместимость. При обмене XML-документами Web-сервисы служат средством переноса. Когда объекты данных попадают в стек Web-сервиса, они последовательно упорядочиваются (сериализуются) в XML-данные. Стеку Web-сервиса на другом конце необходимо знать, как именно привести эти XML-данные в соответствие с требованиями окружения локального приложения (к примеру, десериализировать XML-данных). Подобными отображениями управляют XML-схемы. Задачей XSD-схем является гарантирование того, что исходный тип будет полностью воспроизводим на выходе. Из-за различий в реализациях основных технологий (технология Java™ 2 Platform, Enterprise Edition (J2EE) против Microsoft® .NET), отображения между XSD-схемами и родными типами данных на этих платформах могут отличаться. Одни из этих различий могут привести к ошибке в десериализации, другие – к искажению информации.

В следующих разделах обсуждаются следующие вопросы функциональной совместимости касательно типов данных:

  • Невозможность при помощи инструментов поставщика точно интерпретировать XML-схемы, представляющие собой слабо типизированные коллекции объектов, и отображающие их на правильные родные типы данных.
  • XML-представления массива с нулевыми элементами у .NET и IBM® WebSphere® отличаются.
  • Проблемы с преобразованиями, заключающиеся в потере информации или точности вычислений по причине отсутствия отображения один к одному между родными и XSD типами данных.


В начало


Набор сложных типов данных в сигнатуре метода Web-сервиса

Объекты коллекций могут содержать элементы любых типов данных. По этой причине многие рассматривают их, как слабо типизированные структуры данных, что делает объекты коллекций прекрасным инструментом для программирования. В ООП существует богатые библиотеки типов коллекций, к примеру, в Java такими являются:

  • java.util.Hashtable
  • Vectors
  • Hashmap
  • Set
  • ArrayList

В C#:

  • System.Collections.Hashtable
  • SortedList
  • Queue
  • Stack
  • ArrayList

При использовании в Web-службах, эти типы коллекций могут вызвать непреодолимые проблемы. Проблема заключается в том, насколько принимающая сторона сможет понимать сериализованные сообщения Simple Object Access Protocol (SOAP), содержащие элементы слабо типизированного объекта и типы данных, присущие языку.

Некоторые типы коллекций выглядят очень похожими в разных языках, к примеру, System.Collections.ArrayList в C# и java.util.ArrayList в Java, однако следует помнить, что элементы в коллекциях являются общими связями. Для точной демаршализации (распаковки) XML-представления коллекции, потребители должны обладать информацией об исходных типах. Задачей разработчиков инструментария является интерпретация XML-схем, публикуемых поставщиками Web-сервисов, и отображение SOAP сообщений в типы данных, присущие языку. Для коллекций слабо-типизированных данных такая задача является не простой.

Рассмотрим, как выглядит XML-схема для типов Collection . Представим себе Web-сервис, размещенный в среде Microsoft .NET. Допустим, что класс InventoryService принимает System.Collections.ArrayList, где аргументами являются Product. Этот Web-сервис устанавливает новую цену путем увеличения ее на 10% для каждого продукта в ArrayList и возвращает новый объект типа System.Collections.ArrayList.


Листинг 1. Web-сервис Инвентарь на C#
                
namespace Inventory
{
  [WebService(Namespace="http://services.inventory")]
  public class InventoryService: WebService 
  {
	//increase the product price by 10 percent
	private static float inc_rate = 0.10F;
	public struct Product {
		public string name;
		public int 	qty;
		public float price;
	}
	[WebMethod]
	[XmlInclude(typeof(Product))]
	public ArrayList updateProductPrice(ArrayList products)
	{
		ArrayList newList = new ArrayList();
		IEnumerator eList = products.GetEnumerator();
		while(eList.MoveNext())
		{
		   Product item = (Product)(eList.Current);
		   item.price = item.price * (1 + inc_rate);
		   newList.Add(item);
		} 
		return newList;
	}
   }
}
			

Механизм WSDL в оболочке.NET генерирует XML-схему для ArrayList, типа Collection и сложного типа Product, которая выглядит следующим образом:


Листинг 2. XML-схема для ArrayList и Product
                
1.	<types>
2.	<s:schema xmlns:s="http://www.w3.org/2001/XMLSchema" 
elementFormDefault="qualified" 
targetNamespace="http://services.inventory">
3.	<s:element name="updateProductPrice">
4.	<s:complexType>
5.	<s:sequence>
<s:element maxOccurs="1" minOccurs="0" name="products" 
type="s0:ArrayOfAnyType"/>
6.	</s:sequence>
7.	</s:complexType>
8.	</s:element>
9.	<s:complexType name="ArrayOfAnyType">
10.	<s:sequence>
11.	<s:element maxOccurs="unbounded" minOccurs="0" name="anyType" 
nillable="true"/>
12.	</s:sequence>
13.	</s:complexType>
14.	<s:complexType name="Product">
15.	<s:sequence>
16.	<s:element maxOccurs="1" minOccurs="0" name="name" type="s:string"/>
17.	<s:element maxOccurs="1" minOccurs="1" name="qty" type="s:int"/>
18.	<s:element maxOccurs="1" minOccurs="1" name="price" type="s:float"/>
19.	</s:sequence>
20.	</s:complexType>
21.	<s:element name="updateProductPriceResponse">
22.	<s:complexType>
23.	<s:sequence>
<s:element maxOccurs="1" minOccurs="0" name="updateProductPriceResult" 
type="s0:ArrayOfAnyType"/>
24.	</s:sequence>
25.	</s:complexType>
26.	</s:element>
27.	</s:schema>
28.	</types>
			

В строках с 9 по 13 (См. Листинг 2) задается сложный тип xsd:ArrayOfAnyType с неограниченной последовательностью элементов anyType. ArrayList состоящий из Products транслируется в последовательность анонимных элементов в определении XML-схемы. Этого и следует ожидать, однако здесь существуют две проблемы. Во-первых, другие типы коллекции также будут транслированы в xsd:ArrayOfAnyType. Следовательно, неизвестно, как инструментарий SOAP на другой платформе определит, на какой тип Collection отобразить схему?

Во-вторых, xsd:anyType при незаданном явно типе является типом, установленным по умолчанию. Строка 11 в Листинге 2 является прогнозируемой, так как объекты в Collection являются общими связями – типами не известными во время рабочего цикла. Проблема возникает, когда инструментарий SOAP на другой платформе получает сериализованные объекты. Как правильно десериализовать XML-схему обратно в конкретные объекты без потери смысловой нагрузки?

На самом деле JAX-RPC генерирует следующий вспомогательный класс из схемы xsd:ArrayOfAnyType, представленной на Листинге 2.


Листинг 3. Результирующий вспомогательгый класс для схемы xsd:ArrayOfAnyType
                
public class ArrayOfAnyType  implements java.io.Serializable {
    private java.lang.Object[] anyType;
 <!-- The setter, getter, equals() and hashCode() methods -->
}
			

Из Листинга 3 видно, что неточности в схеме xsd:ArrayOfAnyType вынудили JAX-RPC сгенерировать вспомогательный класс, где в качестве поля с модификатором private вместо конкретного массива Product выступает общий массив java.lang.Object[].

Для разрешения этой неоднозначности вместо xsd:ArrayOfAnyType можно использовать ArrayOfRealType. Вам необходимо лишь определить простой массив конкретных типов (то есть, Product[]) как сигнатуру методов Web-сервиса.

Для Web-сервиса, представленного в Листинге 1 может быть раскрыт фасадный метод:


Листинг 4. Фасад для раскрытия простого массива Product[]
                
[WebMethod]
[XmlInclude(typeof(Product))]
public Product[] updateProductPriceFacade(Product[] products)
{
	ArrayList alist = new ArrayList();
	IEnumerator it = products.GetEnumerator();
	while (it.MoveNext())
		alist.Add((Product)(it.Current));
	alist = updateProductPrice(alist);
	Product[] outArray = (Product[])alist.ToArray(typeof(Product));
	return outArray;
}
			

Новыми схемами для входящей и исходящей частей сообщения являются:


Листинг 5. XML-схема для нового Web-сервиса, представленного в Листинге 4
                
1.	<s:element name="updateProductPriceFacade">
2.	<s:complexType>
3.	<s:sequence>
4.	<s:element minOccurs="0" maxOccurs="1" name="products" 
type="s0:ArrayOfProduct" /> 
5.	</s:sequence>
6.	</s:complexType>
7.	</s:element>
8.	<s:complexType name="ArrayOfProduct">
9.	<s:sequence>
10.	<s:element minOccurs="0" maxOccurs="unbounded" name="Product" 
type="s0:Product" /> 
11.	</s:sequence>
12.	</s:complexType>
13.	<s:element name="updateProductPriceFacadeResponse">
14.	<s:complexType>
15.	<s:sequence>
16.	<s:element minOccurs="0" maxOccurs="1" 
name="updateProductPriceFacadeResult" type="s0:ArrayOfProduct" /> 
17.	</s:sequence>
18.	</s:complexType>
19.	</s:element>
			

В строках кода с 8 по 12 для представления массива Product создана схема xsd:ArrayOfProduct. В этой схеме неоднозначности отсутствуют, в результате чего клиент Web-сервиса не будет иметь проблем с десериализацией массива Products.



В начало


Массив с нулевыми элементами

XML-представления массива с нулевыми элементами в .NET и WebSphere различны. Возьмем для примера Java-метод для Web-сервиса, представленный в Листинге 6.


Листинг 6. Java-метод, возвращающий массив с нулевым элементом
                
public String[] returnArrayWithNull() {
	String[] s = new String[3];
	s[0] = "ABC";
	s[1] = null;
	s[2] = "XYZ";
	return s;
}
			

Элементу типа String s[1] присвоено нулевое значение. Когда клиент .NET вызывает данный метод Web-сервиса, размещенного на платформе WebSphere, массив String сериализуется следующим образом:


Листинг 7. Ответное сообщение Web-сервиса от WebSphere
                
<soapenv:Body>
<returnArrayWithNullResponse xmlns="http://array.test">
<returnArrayWithNullReturn>ABC</returnArrayWithNullReturn>
<returnArrayWithNullReturn xsi:nil="true"/>
<returnArrayWithNullReturn>XYZ</returnArrayWithNullReturn>
</returnEmptyStringResponse>
</soapenv:Body>
			

Второму элементу массива присвоено значение xsi:nil="true". На Java это работает. Java-клиент должен корректно десериализовать второй элемент массива в элемент типа String со значением null. Однако клиент.NET десериализует его вместо нулевой строки в строку нулевой длины. Empty и Null являются совершенно разными объектами в любом языке ООП.

Теперь представим другой метод Web-сервиса, размещенный на WebSphere, как показано в Листинге 8.


Листинг 8. Java-метод с массивами и его сигнатуры ввода и вывода
                
public String[] processArray(String[] args) {
	//do something to the input array and return it back to the client
	return args;
}
			

На этот раз метод Web-сервиса принимает массив в качестве исходных данных, обрабатывает его и возвращает обратно клиенту. Представим, что клиент .NET отправляет массив с нулевым элементом, как показано в Листинге 9.


Листинг 9. Клиент .NET, отправляющий массив с нулевым элементом
                
TestArrayService proxy = new TestArrayService();
string[] s = new string[3];
s[0] = "abc";
s[1] = null;
s[2] = "xyz";
	// Console.WriteLine("the length of the input array = " + 
	s.GetLength(0));
string[] ret = proxy.processArray(s);
	// Console.WriteLine("the length of the output array = " + 
	ret.GetLength(0));
			

В Листинге 10 представлено сообщение запроса SOAP, отправляемое клиентом .NET.


Листинг 10. Сообщение запроса SOAP, отправляемое клиентом .NET
                
<soap:Body>
<processArray xmlns="http://array.test">
<args>abc</args>
<args>xyz</args>
</processArray>
</soap:Body>
			

Мы видим, что нулевой элемент s[1] в запросе SOAP, отправленном клиентом .NET пропущен. В результате этого длина возвращаемого массива не будет совпадать с длиной исходного. Если длина массива или индекс элемента важны для клиентской логики, клиент выдаст ошибку.

Лучшим решением в данных ситуациях будет отказ от передачи массива с нулевыми элементами между клиентами и серверами Web-сервиса.



В начало


Ошибки могут вызывать даже примитивы

XML-схема упрощает функциональную совместимость, обеспечивая модель с разнообразными типами данных. XML-схема определяет специфику типов данных, используемых Web-сервисами, поэтому можно создавать WSDL-сообщения и операции. XSD предлагает широкий диапазон типов и простых структур. Тем не менее, каждый язык программирования имеет набор собственных типов данных. Однозначное отображение между собственными типами данных и типами данных XSD невозможно. Следовательно, информация может быть потеряна во время передачи или принимающая сторона попросту не сможет выполнить отображения определенных собственных типов данных.

Типичными примерами беззнаковых числовых типов являются xsd:unsignedInt, xsd:unsignedLong, xsd:unsignedShort и xsd:unsignedByte. В .NET типы uint, ulong, ushort и ubyte отображаются прямо на соответствующие типы xsd, однако в языке Java беззнаковых числовых типов не существует. Для обеспечения функциональной совместимости в методах Web-сервиса раскрывать подобные числовые типы данных не следует. Вместо этого следует создать методы упаковки, позволяющие раскрывать и передавать эти числовые типы в виде строки xsd:string (в C# используется System.Convert.ToString).

Для типов xsd:decimal, xsd:double и xsd:float каждая платформа имеет разную поддержку точного представления данных. Чтобы избежать потерь в точности представления данных следует протестировать Web-сервис после его интеграции.

Независимо от того, является ли тип данных Значением или Ссылкой, проблемы могут вызывать и сообщающиеся стороны. Объект типа Значение находится в стеке, а объект типа Ссылка – в динамически распределяемой памяти. Это означает, что тип объект типа Ссылка может иметь нулевой указатель, а объект типа Значение не может иметь нулевого значения. Здесь может возникнуть проблема, если в одном языке тип XSD отображается на тип Значение, а в другом – на тип Ссылка. К примеру, xsd:dateTime отображается на System.DateTime, который в C# является объектом типа Значение. Он также отображается на java.util.Calendar, который в Java является типом Ссылка. В действительности, оба типа – и java.util.Date, и java.util.Calendar являются типами Ссылка. Обычно в Java типу Ссылка присваивают нулевое значение, если он не ссылается ни на один объект. Тем не менее, Web-сервис .NET при получении от Java-клиента нулевого значения для их объекта-значения выдаст ошибку System.FormatException. Этого можно избежать, определив сложный тип для упаковки объекта-значения и установив в качестве значения его ссылки null.



В начало


Вывод

В данной статье были представлены некоторые проблемы функциональной совместимости при использовании определенных типов данных. Общими правилами обеспечения функциональной совместимости в таких случаях являются:

  • Придерживайтесь использования простых типов данных, насколько это возможно. В целом избегайте таких сложных типов как ArrayList, Tree, и даже такого распространенного типа, как Hashtable.
  • Хотя в целом простые массивы обеспечивают функциональную совместимость Web-сервисов, проверяйте их содержимое. Убедитесь, что элементы массива имеют одинаковое значение (смысл) на обеих платформах. Избегайте отправки массива с нулевыми элементами.
  • Разберитесь в том, как каждая платформа реализует такие родные примитивы, как float, double и dates and times.

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



Ресурсы



Об авторе

Wangming Ye является Сертифицированным Корпоративным Разработчиком IBM а также Сертифицированным Корпоративным Разработчиком Sun в технологии J2EE. Начинал свою карьеру в качестве разработчика отдела DCE/DFS корпорации Transarc Corporation (в последствии слившейся с IBM), затем являлся одним из главных разработчиков WebSphere Content Distribution Framework в группе WebSphere Edge Server. В настоящее время обеспечивает технические возможности для бизнес-партнеров WebSphere в центре WebSphere Competency Center организации IBM Business Partner Technical Enablement. Связаться с Wangming можно по адресу yme@us.ibm.com.




Выскажите мнение об этой странице


Пожалуйста, найдите минутку и заполните форму, чтобы повысить уровень сервиса.



 


 


 


Поделиться этой статьей:

забобрить забобрить memori сохранить в memori




В начало


IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.
    IBM в России Конфиденциальность Контакты