barbitoff programmer`s blog

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

понедельник, 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>
...
и веб-сервис стартанет без проблем. 

1 комментарий: