barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)
Показаны сообщения с ярлыком JAX-WS. Показать все сообщения
Показаны сообщения с ярлыком JAX-WS. Показать все сообщения

суббота, 25 января 2014 г.

Как я сдавал 1Z0-897 "Oracle Certified Expert, Java EE 6 Web Services Developer"

Сразу оговорюсь, сдал я не особо - 68% при проходном 64%. Сказалась, как обычно, нехватка времени на подготовку, да еще и отсутствие в свободном доступе внятной информации о том, что конкретно будет на экзамене, а также более ли менее близких к составу экзаменационных вопросов книг и mock-экзаменов.
Собственно на подготовку ушла ровно неделя, точнее целиком я готовился только 2 выходных дня, а в остальные 5 дней в среднем по 3-4 часа. Опыт в разработке SOAP веб-сервисов у меня около 2 лет, но на момент начала подготовки я не мог похвастаться особо глубокими знаниями JAX-WS, т.к. разрабатываемые мной веб-сервисы в основном были достаточно тривиальными, и я довольствовался "обязательным минимумом" знаний. Что такое XML Schema и WSDL я знал, но в последнем также не был большим знатоком. REST же для меня был вообще практически новым словом, что это такое, я конечно представлял, но на практике никогда применять не приходилось. Собственно это все и стало предпосылкой к сдаче экзамена, т.к. экзамен - отличный повод "прибраться" в своих знаниях, систематизировать их, а также узнать что-то новое, что потом можно использовать на практике.
При подготовке я в основном ориентировался на содержимое вот этой странички на код-ранче: http://www.coderanch.com/how-to/java/ScdjwsLinks, поэтому первое, с чего я начал подготовку - прочитал книжку "Java Web Services: Up and Running" под авторством Martin Kalin (2009). Книжка по объему достаточно скромная - всего 318 страниц (+ некоторые разделы, например про историю веб-сервисов, можно смело пропускать), поэтому осилить ее можно достаточно быстро. По ходу чтения делал заметки, чтобы перед экзаменом была возможность быстро освежить в памяти полученные из нее знания. Из книги узнал для себя много нового, многие вещи, казавшиеся раньше загадочными, теперь стали очевидными. Не могу сказать, что книга дает исчерпывающие значения по теме, но она определенно показывает, в какую сторону копать при наличии той или иной задачи. Сказать, что этой книги достаточно для успешной сдачи экзамена, тоже с полной уверенностью нельзя. Но об этом немного позже.
После прочтения книги у меня закрались сомнения в том, что полученных знаний хватит для получения сертификата, и я начал судорожно искать, где бы еще что-нибудь почитать по теме. Для начала просмотрел вот этот гайд: http://java.boot.by/ocewsd6-guide/, - там многое пересекается с книгой (даже возникает впечатление, что оно оттуда и скопировано), но в тоже время есть и новая информация, в частности, по REST и JAX-RS. Чтобы окончательно удостовериться в том, что полученные мной знания по REST и JAX-RS достаточно полны, я также прочитал статью на сайте IBM: http://www.ibm.com/developerworks/ru/library/wa-jaxrs/.
В довершение, уже вечером перед экзамен, я пробежался по тестам тут:  http://www.examclouds.com/ (в разделе "WS Quiz"). Тесты меня несколько испугали, т.к. ответы на многие вопросы я не знал. Но как оказалось, это и не нужно - на экзамене ничего подобного не было.
Собственно вот и вся подготовка. Выспаться перед экзаменом не получилось, но свежесваренный кофе сделал свое дело =)
Сдавал я в Unix Education Center, там же, где 10 месяцами ранее я экзаменовался на OCJP. На экзамен дается 1.5 часа, вопросов в тесте - 60. В общем-то, расслабляться нельзя, времени не много. Я успел ответить на все вопросы за 1:15, потом просмотрел еще раз те вопросы, по которым были сомнения. Была пара вопросов, отображавшихся некорректно из-за того видимо, что xml, входящий в текст вопроса, забыли экранировать, и он попросту не показывался. Написал жалобу в pearsonvue, через которых заказывал экзамен, обещали разобраться.
Теперь про вопросы на экзамене. Их уровень не запредельный, обойтись одной только книжкой "Java Web Services: Up and Running" было бы сложно, но в целом, запомни я все прочитанное получше, сдать можно было бы на более высокий балл. Единственная тема, к которой я был совершенно не готов (а на которую, однако, было не менее 4-5 вопросов) - это WS-I.

суббота, 6 июля 2013 г.

Weblogic 10.3.5 + Netbeans 7.3: WSP_1018_POLICY_EXCEPTION_WHILE_FINISHING_PARSING_WSDL

Проблема:

В Netbeans 7.3 создано веб-приложение, содержащее веб-сервис (который создавался с помощью соотв. мастера) и собираемое maven-ом. При развертывании приложения на Wevlogic 10.3.5 валится исключение:
weblogic.application.ModuleException: ...
...
javax.xml.ws.WebServiceException: [failed to localize] WSP_1018_POLICY_EXCEPTION_WHILE_FINISHING_PARSING_WSDL()
...
Caused by: com.sun.xml.ws.policy.PolicyException:[failed to localize] WSP_1014_POLICY_REFERENCE_DOES_NOT_EXIST
...
Причина:

Netbeans включил в pom-ку приложения зависимость webservices-rt как compile, в то время как Weblogic имеет свою имплеменацию jax-ws. Именно наличие в CLASSPATH двух имплементаций приводит к данной ошибке (я правда не понял почему именно, но не суть).

Решение:

Изменить scope зависимости webservices-rt на provided:
    <dependency>
      <groupId>com.sun.xml.ws</groupId>
      <artifactId>webservices-rt</artifactId>
      <version>1.4</version>
      <scope>provided</scope>
    </dependency>
Спасибо http://relativelyprime.blogspot.ru/2010/05/netbeans-68-weblogic-1033-and-jax-ws.html


четверг, 6 июня 2013 г.

jaxws-maven-plugin 2.2: ошибка Error executing: wsimport ... UndeclaredThrowableException: javax.xml.bind.annotation.XmlElementRef.required()

Проблема

При сборке проекта используется jaxws-maven-plugin версии 2.2 для генерации классов по wsdl. Собирается проект на JDK 6. При сборке падает:
Error executing: wsimport ... UndeclaredThrowableException: javax.xml.bind.annotation.XmlElementRef.required()
Под JDK 7 сборка проходит без проблем (ровно как и в связке jaxws-maven-plugin 2.1 + JDK 6). 

Решение

Не понял, чем именно вызвана проблема, но очевидно она связана с тем, что версия плагина - 2.2, тогда как JDK 6 идет с jax-ws / jaxb 2.1. Добавление jax-ws api 2.2 в endorsed при компиляции (как - я уже писал когда-то: http://barbitoff.blogspot.ru/2013/01/maven-wsimport-jdk-16.html) не помогает, что и логично - сборка валится при запуске wsimport, не доходя до компиляции. Проблема решается обновлением плагина jaxws-maven-plugin до версии 2.2.1.

JAX-WS: откуда берутся хост/порт в URL endpoint`ов в публикуемых WSDL

В публикуемых jaxws'ом wsdl хост и порт формируются динамически для каждого запроса исходя из заголовка "Host" http-запроса. 

пятница, 22 марта 2013 г.

JAXWS-RI 2.1.4 на weblogic 10.3.5: java.lang.IllegalArgumentException: com.sun.xml.internal.messaging.sa aj.soap.LocalStrings != com.sun.xml.messaging.saaj.soap.LocalStrings

Проблема:

Есть приложение, использующее JAXWS-RI 2.1.4 (поставляется вместе с библиотеками ri в WEB-INF/lib), развернутое на weblogic 10.3.5. В начале при попытке вызова в приложении jaxws-клиента к удаленному веб-сервису падала ошибка:
java.lang.ExceptionInInitializerError
        at com.sun.xml.ws.api.addressing.WSEndpointReference.toSpec(WSEndpointReference.java:637)
...
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "address". Use @XmlType.name and @XmlType.namespace to assign different names to them.
После некоторых поисков решение было найдено тут: http://metro.java.net/guide/ch02.html#weblogic-10. В соответствии с этой инструкцией в weblogic.xml было прописано:
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">
<weblogic-web-app>
   <description>Weblogic Webapp</description>
   <container-descriptor>
      <prefer-application-packages>
         <package-name>com.ctc.*</package-name>
         <package-name>com.sun.xml.*</package-name>
         <package-name>com.sun.istack.*</package-name>
         <package-name>com.sun.msv.datatype.*</package-name>
         <package-name>com.sun.msv.driver.*</package-name>
         <package-name>com.sun.msv.grammar.*</package-name>
         <package-name>com.sun.msv.reader.*</package-name>
         <package-name>com.sun.msv.relaxns.*</package-name>
         <package-name>com.sun.msv.scanner.*</package-name>
         <package-name>com.sun.msv.util.*</package-name>
         <package-name>com.sun.msv.verifier.*</package-name>
         <package-name>com.sun.msv.writer.*</package-name>
         <package-name>com.sun.org.apache.xml.internal.*</package-name>
         <package-name>com.sun.wsit.*</package-name>
         <package-name>javax.jws.*</package-name>
         <package-name>javax.xml.bind.*</package-name>
         <package-name>javax.xml.soap.*</package-name>
         <package-name>javax.xml.stream.*</package-name>
         <package-name>javax.xml.ws.*</package-name>
         <package-name>javax.xml.activation.*</package-name>
         <package-name>javax.xml.annotation.*</package-name>
         <package-name>javax.xml.mail.*</package-name>
         <package-name>javax.xml.security.*</package-name>
         <package-name>javax.xml.registry.*</package-name>
         <package-name>javax.xml.rpc.*</package-name>
         <package-name>javax.xml.crypto.*</package-name>
         <package-name>javanet.staxutils.*</package-name>
         <package-name>jp.gr.xml.*</package-name>
         <package-name>org.codehaus.stax2.*</package-name>
         <package-name>org.glassfish.gmbal.*</package-name>
         <package-name>org.iso_relax.*</package-name>
         <package-name>org.jcp.xml.dsig.*</package-name>
         <package-name>org.jvnet.*</package-name>
         <package-name>org.relaxng.*</package-name>
         <package-name>org.apache.commons.*</package-name>
         <package-name>org.apache.xerces.*</package-name>
         <package-name>javax.namespace.xml.*</package-name>
      </prefer-application-packages>
      <prefer-application-resources>
         <resource-name>META-INF/services/javax.xml.ws.*</resource-name>
         <resource-name>META-INF/services/com.sun.xml.ws.*</resource-name>
         <resource-name>META-INF/services/com.sun.tools.ws.*</resource-name>
      </prefer-application-resources>
   </container-descriptor>
</weblogic-web-app>

А в WEB-INF/classes были закинуты классы в соответствие с п.3 раздела "Known Issues" по той же ссылке. 
Однако, счастья не наступило, ошибка превратилась в:
java.lang.IllegalArgumentException: com.sun.xml.internal.messaging.sa aj.soap.LocalStrings != com.sun.xml.messaging.saaj.soap.LocalStrings
При последующих вызовах стало падать просто:
java.lang.NoClassDefFoundError: Could not initialize class com.sun.xml.ws.api.BindingID  
Причина:

Причина в поставляемой с приложением библиотеке saaj-impl (она в него пришла вместе с зависимостью от JAXWS-RI), а именно в конфликте содержащегося в ней класса com.sun.xml.messaging.saaj.soap.SAAJMetaFactoryImpl с классом  com.sun.xml.internal.messaging.saaj.soap.SAAJMetaFactoryImpl из rt.jar в JDK (подробнее причина описана тут: http://azagozdzinski.wordpress.com/2011/02/15/saaj-problem/). Сначала проблема вылечилась достаточно просто, добавлением в weblogic.xml следующей строки:
<prefer-application-resources>
<resource-name>META-INF/services/javax.xml.ws.*</resource-name>
<resource-name>META-INF/services/javax.xml.soap.*</resource-name>
<resource-name>META-INF/services/com.sun.xml.ws.*</resource-name>
<resource-name>META-INF/services/com.sun.tools.ws.*</resource-name>
</prefer-application-resources>
Однако, вскоре проблема вернулась обратно. Оказалось, на тот же weblogic было задеплоено другое приложение, также идущее со своим JAX-WS RI, однако более поздней версии - 2.2 (и соответственно, библиотеками saaj-api-1.3.4 и saaj-impl-1.3.19 против 1.3 и 1.3.1 соотв. в моем приложении). На этот раз беда решилась обновлением saaj в моем приложении до тех же 1.3.4 и 1.3.19.
Вот такие вот беды вызывает желание использовать несколько имплементаций JAX-WS в пределах одной JVM (в конечном счете их оказалось аж 3: родная имплементация weblogic'а, а также 2 разные версии jaxws-ri).

суббота, 9 февраля 2013 г.

com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.internal.bind.api.JAXBRIContext

Проблема:

Есть веб-приложение, которое тащит с собой (в WEB-INF/lib) api и имплементацию JAXB, а именно, jar-ники:
  • jaxb-api.jar - версии 2.1
  • jaxb-impl.jar - версии 2.1.4

В приложении используется JAX-WS клиент к веб-сервису. При попытке отправить с помощью него запрос валится:

java.lang.ExceptionInInitializerError
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:239)
...
Caused by: java.lang.ClassCastException: com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.internal.bind.api.JAXBRIContext
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.<clinit>(SOAPFaultBuilder.java:488)
...
Что примечательно, проблема не воспроизводится на Tomcat 7, а вылезает только на Tomcat 6. 

Причина:

Причина ClassCastException заключается в данном случае в том, что один класс (JAXBContextImpl) тянется из jaxb-impl в WEB-INF, а второй (JAXBRIContext) - из стандартной имплементации JAX-WS из JDK. Первый грузится ClassLoader`ом каталины, второй же - bootstrap`ом. Однако почему-то на 7ом томкате это не приводит с ClassCastException.

Решение:

Раз уже приложение идет со своим JAXB, то и JAX-WS придется также поставлять с ним. В моем случае это означало добавление в pom-ку зависимости:
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.1.4</version>
<scope>runtime</scope>
</dependency>


пятница, 11 января 2013 г.

jaxws-maven-plugin 2.1 и "unmappable character for encoding UTF-8"

Проблема:

В проекте используется jaxws-maven-plugin версии 2.1, генерирующий классы по WSDL. В WSDL и импортируемой в неё схеме есть русские буквы в аннотациях. При сборке проекта при компиляции возникают ошибки "unmappable character for encoding UTF-8" при попытке скомпилировать сгенерированные классы. ОС - Windows, кодировка исходников проекта - UTF-8.

Причина:

Проект использует кодировку исходников UTF-8. wsimport генерирует исходники в cp1251 (в системной кодировке), причем они содержат русские символы в комментариях, пришедшие туда из аннотаций к XSD-схеме.
В отличие от wsimport`а версии 2.2, опции "encoding", позволяющей задать кодировку целевых файлов, нет. Нет такой опции и у используемого им xjc (эту опцию можно было бы передать ему через опцию -B<xjcoption> wsimport`а).

Решение:

Как ни странно, помогла установка параметра xnocompile в false:
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.1</version>
<!-- ... -->
<configuration>
<sourceDestDir>${project.build.directory}/generated-sources/jaxws-wsimport</sourceDestDir>
<xnocompile>false</xnocompile>
<verbose>true</verbose>
<extension>true</extension>
<catalog>${basedir}/src/jax-ws-catalog.xml</catalog>
</configuration>
</plugin>
Также xnocompile можно установить в false не в конфигурации всего плагина, а внутри конфигурации execution`а, эффект тот же:
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.1</version>
<executions>
 <execution>
<goals>
 <goal>wsimport</goal>
</goals>
<configuration>
 <xnocompile>false</xnocompile>
 <!-- ... -->
</configuration>
<!-- ... -->
 </execution>
</executions>
<!-- ... -->
</plugin>
Генерируемые исходники все также в cp1251, но компиляция проходит. Есть идея, что это происходит потому, что сгенерированные файлы компилируются сразу wsimport`ом, и в этом случае компилятор не обращает внимание на кодировку файлов проекта (посколько о ней не знает), а читает исходники в системной кодировке, в какой они и действительно закодированы.

четверг, 10 января 2013 г.

maven и jaxws-maven-plugin 2.2: проблема со сборкой на JDK 1.6.

Проблема:

Имеется проект, собираемый maven`ом с использованием jaxws-maven-plugin версии 2.2. Проект без проблем собирается с использованием JDK 1.7, однако при попытке собрать его на JDK 1.6 возникает ошибка:
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project Fileadapter-ECM-WS: Compilation failure: Compilation failure:
symbol  : constructor Service(java.net.URL,javax.xml.namespace.QName,javax.xml.ws.WebServiceFeature[])
location: class javax.xml.ws.Service
Добавление в проект зависимости от jaxws-api 2.2:
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.2.8</version>
<scope>compile</scope>  
</dependency>

не помогает, т.к. при компиляции используется jaxws-api из JDK, а там, в случае JDK 1.6, находится версия jaxws-api 2.1.

Решение:

Уже когда-то писал про аналогичную проблему (http://barbitoff.blogspot.ru/2012/01/cannot-find-symbol-symbol-constructor.html), правда тогда собирал ant`ом, а не maven`ом. 
Решения, вобщем-то, два. Первое - перейти на jaxws-maven-plugin версии 2.1. Второе - использовать endorsed-механизм, чтобы заменить версию jaxws-api при сборке (если мы знаем, что в целевой среде, где будет выполняться приложение, будет jaxws-api версии 2.2 и реализующая его имплементация). Делается это следующим образом:
1) Во-первых, в проекте необходимо создать папку для endorsed-библиотек. Я создал её в корне проекта (на одном уровне с pom.xml) и называл "endorsed".
2) В созданную папку поместить jar-ник jaxws-api версии 2.2, скачать его можно тут.
3) Настроить maven-compiler-plugin на использование нашей endorsed-папки:
<build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
          <compilerArguments>
            <endorseddirs>${basedir}/endorsed</endorseddirs>
          </compilerArguments>
        </configuration>
      </plugin>
      <!-- ... -->
</build>
PS Конечно, правильнее с точки зрения философии maven будет не класть заранее jar-ник в папку endorsed, а размещать эту папку в директории сборки и копировать туда jar-ник как зависимость с помощью dependency-плагина уже при сборке.

понедельник, 31 декабря 2012 г.

WSO2 ESB: как заставить прокси сервис использовать SOAP 1.1 в исходящих сообщениях

Проблема:

Есть прокси-сервис на WSO2 ESB 4.5.1, вызывающий конечный веб-сервис по http. Конечный сервис реализован на JAX-WS и использует версию SOAP 1.1. При попытке использовать SOAP 1.2 (используемый шиной по-умолчанию) валится с исключением:
com.sun.xml.ws.server.UnsupportedMediaException: Unsupported Content-Type: application/soap+xml; charset=UTF-8; action="xxx" Supported ones are: [text/xml]
Необходимо заставить прокси-сервис WSO2 использовать именно версию 1.1.

Решение:

Добавить атрибут format="soap11" в настройку конечной точки на шине:
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="[EP_NAME]">
    <address format="soap11" statistics="disable" trace="disable" uri="[EP_URI]">
...

пятница, 28 декабря 2012 г.

com.sun.istack.internal.SAXException2: unable to marshal type as an element because it is not known to this context

Проблема:

Есть набор классов, сгенерированных wsimport`ом. Расположены эти классы в пакете "my.package". В проекте в этот же пакет добавлен ещё один класс "MyExtraClass", и есть желание выполнить его маршаллизацию:
MyExtraClass obj = new MyExtraClass();
...
JAXBContext jc = JAXBContext.newInstance("my.package");
Marshaller marshaller = jc.createMarshaller();
StringWriter xmlWriter = new StringWriter();
marshaller.marshal(obj, xmlWriter); 
Однако, последний вызов валится с исключением:
com.sun.istack.internal.SAXException2: unable to marshal type "my.package.MyExtraClass" as an element because it is not known to this context
Т.е., по-видимому, JAXB этого класса по какой-то причине не видит.

Причина:

wsimport, помимо классов, соответствующих XML-типам, сгенерировал в пакете my.package также класс ObjectFactory, определяющий, какие классы будут известны JAXB-контексту. Естественно, эта ObjectFactory о новом классе MyExtraClass ничего не знает, поэтому ничего о нем не знает и JAXB-контекст.

Решение:

Т.к. ObjectFactory менять не хочется, он ведь генерируется при компиляции автоматически, нужно добавить наш MyExtraClass в JAXB-контекст каким-то другим способом. Для этого подойдет такой вариант:
  1. Создать в пакете "my.package" файл "jaxb.index"
  2. Записать в этот файл название нашего класса, без указания пакета, т.е. просто:
    MyExtraClass
Все, теперь класс будет маршаллизироваться без проблем.

вторник, 25 декабря 2012 г.

JAX-WS: обертка ответов от разных веб-методов в одинаковые теги

Задача:

В JAX-WS-веб-сервисе (используется имплементация JAX-WS RI)  есть несколько методов, возвращающих объекты одного типа (пусть это будет класс OperResultClass):
@WebMethod(operationName = "operationA")
public OperResultClass operationA(){...}
@WebMethod(operationName = "operationB")
public OperResultClass operationB(){...}
@WebMethod(operationName = "operationC")
public OperResultClass operationC(){...}...
Необходимо, чтобы XML, получаемый на их выходе, выглядел так:
<MyResponseWrapperTag xmlns="http://soap.response">
<MyResponseTag>
<!-- содержимое объекта-ответа -->
</MyResponseTag>
</MyResponseWrapperTag>
Т.е. необходимо задать для всех методов:
  1. Имя наружного тега и его пространство имен
  2. Имя внутреннего тега и его пространство имен

Решение:

Второй пункт делается просто: каждый метод аннотируется следующим образом:
@WebResult(name="MyResponseTag", targetNamespace="http://soap.response")
После этого мы будем иметь правильный внутренний тег, а вот наружный будет генерироваться JAX-WS`ом автоматически, основываясь на имени метода (он будет состоять из имени метода + "Response").

Для задания имени наружного тега используется аннотация @ResponseWrapper. Но использовать её так:
  @ResponseWrapper(
          localName="MyResponseWrapperTag",
          targetNamespace="http://soap.response"
        )
не получится - будет валиться исключение:
Two classes have the same XML type name "{http://soap.response}MyResponseWrapperTag". Use @XmlType.name and @XmlType.namespace to assign different names to them.
Тут дело в том, что для оберток вокруг ответа JAX-WS генерирует свои классы, по одному на каждый метод. Т.о, для каждого веб-метода будет использоваться свой класс, в то время как из-за @ResponseWrapper всем им будет назначен одно и тот же имя XML-типа. 
Выход из ситуации - самостоятельно задавать имя класса-обертки, чтобы JAX-WS не генерировал своих классов. Делается это следующим образом:
@ResponseWrapper(          className="my.MyResponseWrapper",
          localName="MyResponseWrapperTag",
          targetNamespace="http://soap.response"
        )
Теперь нужно создать этот самый класс-wrapper "my.MyResponseWrapper". Он будет выглядеть примерно так:
@XmlType(name="MyResponseWrapperType",namespace="http://soap.response")
@XmlAccessorType(XmlAccessType.FIELD)
public class MyResponseWrapper{
  @XmlElement(name="MyResponseTag",namespace="http://soap.response")
  public OperResultClass MyResponseTag;
}
Здесь важно, чтобы параметры аннотации @XmlElement совпадали с таковыми в аннотации @WebResult метода. Namespace можно не указывать, если он задан на уровне пакета в package-info.java:
@XmlSchema(namespace = "http://soap.response", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package my;
import javax.xml.bind.annotation.XmlSchema;



вторник, 18 декабря 2012 г.

javax.xml.ws.spi.FactoryFinder$ConfigurationError

Проблема:

При попытке в приложении создать объект клиента к веб-сервису, построенного на JAX-WS, валится исключение:
javax.xml.ws.spi.FactoryFinder$ConfigurationError: Provider org.apache.cxf.jaxws.spi.ProviderImpl not found
Причина:

Где-то в CLASSPATH переопределен JAX-WS провайдер на Apache Cxf, при этом самого Cxf в CLASSPATH нет (ну или, если используется OSGI, он может быть просто не импортирован).

Решение:

Возможных решения, в общем-то, 3:
  • Найти и положить в CLASSPATH / импортировать бандл Cxf
  • Найти, где в CLASSPATH переопределен JAX-WS-провайдер и удалить переопределение. Переопределяется он файлом META-INF/services/javax.xml.ws.spi.Provider, в который записано имя класса провайдера.
  • Переопределить провайдер обратно в своем приложении так, чтобы Ваш файл лежал в CLASSPATH ближе, чем вражеский. В случае с собираемым Maven`ом приложением нужно создать файл src/main/resources/META-INF/services/javax.xml.ws.spi.Provider, и записать в него (если Вы хотите вернутся к провайдеру по-умочанию, который идет с JDK): 
    com.sun.xml.internal.ws.spi.ProviderImpl


среда, 17 октября 2012 г.

JAX-WS-клиент веб-сервиса: ошибка "com.sun.xml.internal.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class <xxx> is not found. Have you run APT to generate them?"

Проблема:

Веб-приложение, использующее JAX-WS-клиент к веб-сервису, отлично работало на машине разработчика, а при развертывании на Tomcat на промышленном сервере стало валиться с ошибкой:
com.sun.xml.internal.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class <xxx> is not found. Have you run APT to generate them?
Причина:

Вероятнее всего, старый JDK.

Решение:

Обновить JDK. Не знаю, до какой версии точно, но обновление до последнего JDK (1.6.0_26 в  репозитории Debian Lenny) в моем случае решило проблему. 

понедельник, 17 сентября 2012 г.

JAX-WS: IllegalAnnotationsException "Two classes have the same XML type name" на ровном месте

Проблема:

Есть веб-сервис, построенный на JAX-WS, у которого есть веб-метод, реализующий soap-операцию "op", тип его возврата - OpResponse: 
@WebService(serviceName = " MyService ")
public class MyService
{
...
@WebMethod(operationName = "op")
public OpResponse op(...) {...}
...
}
...
public class OpResponse { ... }
При развертывании этого веб-сервиса валится ошибка:
com.sun.xml.ws.transport.http.servlet.WSServletException: WSSERVLET11: failed to parse runtime descriptor: javax.xml.ws.WebServiceException: Unable to create JAXBContext
...
Caused by: javax.xml.ws.WebServiceException: Unable to create JAXBContext
...
Caused by: java.security.PrivilegedActionException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{...}opResponse". Use @XmlType.name and @XmlType.namespace to assign different names to them.
Хотя вроде бы никаких двух классов с одинаковым XML-типом в проекте нет (впрочем, XML-типы пока явно вообще нигде не фигурируют).

Причина:

Причину ошибки можно объяснить с двух сторон - с точки зрения классов или с точки зрения генерируемых jaxws`ом WSDL/XSD. Я приведу второе объяснение.
Генерируя WSDL, JAX-WS использует имя "opResponse" как имя XSD-типа ответа операции "op" (т.е. он просто конкатенирует имя операции и "Response"), который потом уже, в XSD-схеме, раскрывается с использованием XSD-типа, соответствующего возвращаемому Java-классу:
<operation name="op">
<input wsam:Action="http://.../opRequest" message="tns:op"/>
<output wsam:Action="http://.../opResponse" message="tns:opResponse"/>
</operation>
<xs:complexType name="opResponse">
<xs:sequence>
<xs:element name="return" type="tns:<responseClassName>" minOccurs="0"/>
</xs:sequence>
</xs:complexType> 
Здесь <responseClassName> - это имя класса, который является типом возврата метода "op", написанное со строчной первой буквы. В нашем случае это имя должно было бы быть равным снова "opResponse", т.к. тип возврата метода "op" - именно класс OpResponse, что сделало бы XSD-схему некорректной.

Решение:

Аннотировать класс OpResponse с помощью аннотации @XmlType, как и советует JAX-WS, так, чтобы имя XSD-типа, соответствующего классу OpReponse, отличалось от "opResponse", например:
@XmlType(name = "OpResponseType")
public class OpResponse {...}
Тогда схема примет вид:
...
<xs:complexType name="opResponse">
 <xs:sequence>
  <xs:element name="return" type="tns:OpResponseType" minOccurs="0"/>
 </xs:sequence>
</xs:complexType>
...
и веб-сервис стартанет без проблем. 

среда, 7 марта 2012 г.

Настройка таймаута запроса к SOAP-веб-сервису в JAX-WS

Задача:

Явно задать таймаут запроса к SOAP-веб-сервису, клиент которого создан с помощью wsimport.

Решение:

Как ни странно, найти решение оказалось непросто. Во-первых, решение зависит от сервера приложений, т.е. конкретной реализации JAX-WS, т.к., насколько я понял, спецификация JAX-WS такого функционала не предусматривает.
В любом случае проблема решается установкой неких свойств в контексте запроса следующим образом:
<ServiceName> serv = new <ServiceName>();
<PortTypeName> port = confServ.get<PortName>();
((BindingProvider) port).getRequestContext().put(<ParameterName>, iTimeoutValue);
, где ServiceName - имя SOAP-сервиса, PortName - имя порта, PortTypeName - имя типа порта (эти классы были сгенерированы wsimport`ом), iTimeoutValue - величина таймаута, которую хотим установить, ParameterName - имя параметра, зависящее от реализации JAX-WS. 
Для Tomcat 6 достаточно установки свойства JAXWSProperties.REQUEST_TIMEOUT, однако видел также рекомендации по установке свойств JAXWSProperties.CONNECT_TIMEOUT и BindingProviderProperties.REQUEST_TIMEOUT, так что можно на всякий случай устанавливать все 3. Для JBoss используется свойство org.jboss.ws.core.StubExt.StubExt.PROPERTY_CLIENT_TIMEOUT (http://stackoverflow.com/questions/2592303/how-do-i-set-the-jax-ws-client-request-timeout-programatically-on-jboss).
Если при сборке проекта возникают ошибки типа "package com.sun.xml.internal.ws.client does not exist", решение описано здесь: http://barbitoff.blogspot.com/2012/03/comsunxmlinternalws.html.

пятница, 13 января 2012 г.

cannot find symbol symbol : constructor Service(java.net.URL,javax.xml.namespace.QName,javax.xml.ws.WebServiceFeature[]) location: class javax.xml.ws.Service super(wsdlLocation, CONFIRMSERVICE_QNAME, features);

Проблема: 
При компиляции проекта, использующего JAX-WS и клиент веб-сервиса, сгенерированный по WSDL, вылетает ошибка, ругающаяся на код, сгенерированный wsimport`ом:
cannot find symbol symbol : constructor Service(java.net.URL,javax.xml.namespace.QName,javax.xml.ws.WebServiceFeature[]) location: class javax.xml.ws.Service super(wsdlLocation, CONFIRMSERVICE_QNAME, features);
Причина:
Wsimport и компилятор используют разные версии JAX-WS (например, wsimport использует 2.1, а компилятор - 2.2).

Решение:
Исправить либо библиотеки, используемые компилятором, либо используемые wsimport`ом (первый использует библиотеки, подключенные к проекту, а второй - библиотеки JDK, их можно переопределить через endorsed-механизм).