Нь дя... впечатлений получилось много:) Сейчас попробую вкратце описать их.
Цели и исходные условия
Есть WEB application - представляет собой нечто, предоставляющее веб сервисыЕсть клиенты 3-x типов: Java (XFire), Java (CXF) и Flex.
Задачу можно сформулировать следующим образом – перевести веб приложение
на CXF без изменений на клиентах.
Трудности (и не только)
Вот некоторые трудности (и не только), с которыми пришлось столкнутся:1. Да здравствует Java 5!
Мы используем «XSD first" схему, т.е. вначале мы создаем XML схемы с описанием используемых сущностей, потом генерируем Java классы. Вот тут то получилась первая неожиданность: XFire для биндинга использует JAXB 1.0, а CXF – JAXB2 и это дает следующие бонусы:- generics, т.е. JAXB2 генерирует нормальные
параметризированные коллекции и это очень удобно! - перечисления (enum)
<xsd:simpleType name="valueType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="TYPE_1"/> <xsd:enumeration value="TYPE_2"/> <xsd:enumeration value="TYPE_3"/> </xsd:restriction> </xsd:simpleType> .. <xsd:element name=”type” type=”valueType” />
XFire (точнее JAXB) преобразовывает это в строку, т.е. получается просто
и нeзатейлево:
String getType(); void setType(String type);/* Вот сюда можно передать что угодно*/CXF (точнее JAXB2) в этом случае генерирует enum (со всеми вытекающими удобствами).
2. Краткость сестра таланта
XFire генерировал великое множество интерфейсов, фибрику (класс ObjectFactory) и такое же великое множество классов имплементаций. В итоге пользоваться "Этим" как DOM было не слишком то и удобно. JAXB2 генерирует аннотированные классы (POJO), и работать с такой моделью стало на порядок приятней.3. JSR 181 аннотации вместо Aegis XML
XFire использует Aegis биндинг, а это значит что для объявления веб сервиса необходимо написать java интерфейс, а рядышком положить XML файл, примерно вот с таким контентом:<mappings> <mapping uri="" name=""> <method name="methodName"> <return-type mappedName=""/> <parameter index="1" mappedName="param1"/> <parameter index="2" mappedName="param2"/> </method> </mapping> </mappings>По моему, не очень удобно когда информация об интерфейсе находится в 2 местах – в Java и XML файлах.
CXF предлагает использовать JSR 181 аннотации, а это значит что открыв Java интерфейс можно получить/задать всю необходимую информацию. И это удобно (да простят меня "фанаты" XML)!
4.Как передать/получить Map<string, string> ? И подобные вопросы
Вот здесь то появилась первая трудность – CXF не умет мапить Map, DataSource, java.util.Calendar и некоторые другие вещи. Пришлось немного почитать чтобы восполнить этот «пробел»- Маппинг Map. Используем аннотации @XmlJavaTypeAdapter и класс XmlAdapter. Неудобство заключается в том, что необходимо создать 3 дополнительных классов: XML представление и
class String2String{ List<Entry> entry = null; } class Entry { String key = null; String value = null; }
И класс адаптер, преобразующий объект типа String2String в объект типа Map<String, String>
- DataSource (передача бинарных данных). По умолчанию CXF предлагает использовать byte[], что не очень удобно(мягко говоря). Немного почитав документацию, обнаружился класс DataHandler (... и настроение улучшилось :) )
- Calendar. Поумолчанию CXF предлагает использовать XMLGregorianCalendar. "Проблема" решилась применением кастомизации биндинга. Например читаем вот тут .
5. Краткость сестра таланта – часть2
Выяснилась неприятная «наклонность» XFire генерировать кучу оберток. Например для методов
void someMethod(String [] ids); //или void someMethod(List<String> ids);CXF в WSDL помещает нечто подобное
<xsd:element name="ids" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
Но вот XFire считает совершенно необходимым обернуть коллекцию ids:
<xsd:element name="ids"> <xsd:complexType> <xsd:sequence> <xs:element name="string" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /> </xsd: sequence > </xsd:complexType> </xsd:element>Ну просто замечательно, блин! Пришлось вручную создавать классы оберток, и в методы вместо String[] ids передавать нечто вроде: ArrayOfString ids…
6. Подключаем исходные XSD в WSDL
В XFire была замечательная возможность подключение наших XSD в результирующий WSDL (c полным сохранением "вида схемы", комментариев и т.д.). В CXF такое сделать не получилось. В итоге получаем двойное преобразование XSD to Java и Java to XSD. Понятно, что в этом случае начальные и конечные схемы чуть отличаются, все комментарии теряются... ну и вообще, двойная генерация как то не очень солидно смотрится. Возможно здесь подход "Java first" показал бы себя намного лучше.7. И еще кое что...
Отдельные приключения были с маппингом исключений(java exception в wsdl failt), с работой утилиты wsdl2java с XSD конструкциями choise, с получением нужных namespace-ов в итоговом wsdl и другими «мелкими» недоразуменияыми.Итого:
Результат – сервер перевести получилось, а вот обойтись без изменения клиентов не получилось (хотя эти изменения довольно незначительные). Вообщем то, как сказал наш лид: «...выяснилось что это возможно, хотя и заняло много времени...».А лично у меня осталось довольно таки противоречивое впечатление от CXF + JAXB2. С одной стороны вроди бы и круто: тут тебе и Java 5, и использование POJO и вооще, многие запчасти сейчас уже вошли в Core Java… Но с другой стороны наблюдается некая недоработанность и неуправляемость фреймверка: поведение утилит довольно сильно меняется от версии к версии, причем речь идет о изменениях в 3-ем знаке (2.2.5 и 2.2.6); не все механизмы очевидны и управляемы, да и документация как то не очень - простые вещи описаны ну очень подробно, а вот что то посложнее – "go to google".
Вот так вот.
Вот связанные статьи:
Шаг 0 - XSD to Java
Шаг 1 - Описание Java модели и SEI (//TODO)
Шаг 2 - Генерация клиента (WSDL to Java) (//TODO)
блоггер не врапит <>, во всяком случае он не делает этого по-умолчанию.
ОтветитьУдалитьНь дя... Поправить то поправил, но как то не очень удобно получается...
ОтветитьУдалить