为何maven-jaxb2-plugin不生成wsdl:message的Java类?如何解决?
问题:maven-jaxb2-plugin不生成wsdl:message对应Java类的原因及解决办法
按照Spring官方指南《Consuming a SOAP web service》创建SOAP服务客户端时,遇到一个问题:maven-jaxb2-plugin没有从WSDL文件生成wsdl:message对应的Java类,只生成了schema相关的简单类型。导致调用getWebServiceTemplate().marshalSendAndReceive()时必须手动构造请求对象。
使用的WSDL文件如下:
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://www.test.com/soap/jacky/client" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://www.test.com/soap/jacky/client"> <wsdl:types/> <wsdl:message name="retrieveResponse"> <wsdl:part name="retValue" type="xsd:string"/> </wsdl:message> <wsdl:message name="retrieveRequest"> <wsdl:part name="name" type="xsd:string"/> <wsdl:part name="flag" type="xsd:boolean"/> </wsdl:message> <wsdl:portType name="DemoSoap"> <wsdl:operation name="retrieve" parameterOrder="name flag"> <wsdl:input message="tns:retrieveRequest" name="retrieveRequest"/> <wsdl:output message="tns:retrieveResponse" name="retrieveResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="DemoBinding" type="tns:DemoSoap"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="retrieve"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="retrieveRequest"> <wsdlsoap:body use="literal"/> </wsdl:input> <wsdl:output name="retrieveResponse"> <wsdlsoap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="DemoClient"> <wsdl:port binding="tns:DemoBinding" name="Demo"> <wsdlsoap:address location="http://www.test.com/soap/jacky/client"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
原因分析
- 你的WSDL采用了RPC/literal风格:在
<wsdl:binding>里明确指定了style="rpc",这种风格下,JAXB默认不会为wsdl:message生成专门的封装类,而是直接使用message part对应的简单类型(比如String、Boolean)作为方法参数和返回值。 - JAXB的核心是处理XML Schema定义的类型,而RPC风格的message parts直接引用了XSD内置的简单类型,没有在
<wsdl:types>里定义对应的复杂类型,所以maven-jaxb2-plugin不会生成请求/响应的封装类。
解决办法
方法1:修改WSDL为Document/literal风格(推荐)
Document风格是当前SOAP服务的主流规范,它基于XML Schema定义请求和响应的结构,JAXB能自动生成对应的封装类。修改后的WSDL示例如下:
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://www.test.com/soap/jacky/client" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://www.test.com/soap/jacky/client"> <wsdl:types> <xsd:schema targetNamespace="http://www.test.com/soap/jacky/client"> <xsd:element name="retrieveRequest"> <xsd:complexType> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="flag" type="xsd:boolean"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="retrieveResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="retValue" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </wsdl:types> <wsdl:message name="retrieveResponse"> <wsdl:part name="parameters" element="tns:retrieveResponse"/> </wsdl:message> <wsdl:message name="retrieveRequest"> <wsdl:part name="parameters" element="tns:retrieveRequest"/> </wsdl:message> <wsdl:portType name="DemoSoap"> <wsdl:operation name="retrieve"> <wsdl:input message="tns:retrieveRequest" name="retrieveRequest"/> <wsdl:output message="tns:retrieveResponse" name="retrieveResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="DemoBinding" type="tns:DemoSoap"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="retrieve"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="retrieveRequest"> <wsdlsoap:body use="literal"/> </wsdl:input> <wsdl:output name="retrieveResponse"> <wsdlsoap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="DemoClient"> <wsdl:port binding="tns:DemoBinding" name="Demo"> <wsdlsoap:address location="http://www.test.com/soap/jacky/client"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
修改后重新执行maven生成命令,插件会自动生成RetrieveRequest和RetrieveResponse类,直接用于marshalSendAndReceive调用即可。
方法2:改用jaxws-maven-plugin(适配RPC风格)
如果无法修改WSDL,可以换用jaxws-maven-plugin,它对RPC风格的WSDL支持更好,会自动生成包含请求/响应封装类的客户端代码。在pom.xml中添加如下配置:
<plugin> <groupId>org.jvnet.jax-ws-commons</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>2.3</version> <executions> <execution> <goals> <goal>wsimport</goal> </goals> <configuration> <wsdlFiles> <wsdlFile>src/main/resources/your.wsdl</wsdlFile> </wsdlFiles> <packageName>com.test.soap.jacky.client</packageName> <keep>true</keep> </configuration> </execution> </executions> </plugin>
执行mvn jaxws:wsimport命令后,会生成包含Retrieve、RetrieveRequest、RetrieveResponse等类的客户端代码,直接调用即可。
方法3:添加JAXB绑定文件(不推荐)
如果必须使用maven-jaxb2-plugin,可以创建一个JAXB绑定文件强制生成封装类,但这种方式兼容性较差。
创建bindings.xjb文件:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" version="2.1"> <jaxb:bindings wsdlLocation="your.wsdl" node="/wsdl:definitions/wsdl:portType/wsdl:operation[@name='retrieve']"> <jaxb:enableWrapperStyle>true</jaxb:enableWrapperStyle> </jaxb:bindings> </jaxb:bindings>
然后在maven-jaxb2-plugin配置中引用该文件:
<plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifactId> <version>0.14.0</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <wsdl>src/main/resources/your.wsdl</wsdl> <bindingDirectory>src/main/resources</bindingDirectory> <bindingFiles> <bindingFile>bindings.xjb</bindingFile> </bindingFiles> </configuration> </execution> </executions> </plugin>
内容的提问来源于stack exchange,提问作者Jacky Wang
相关产品推荐
相关产品推荐

