使用CXF生成SOAP客户端报错:无带@XmlElementDecl的ObjectFactory
使用CXF 3.4.2 codegen Maven插件生成SOAP客户端存根,初始化服务存根时出现大量如下错误:
There's no ObjectFactory with an @XmlElementDecl for the element {http://tempuri.org/}travelDocumentNumber.
this problem is related to the following location:
at protected javax.xml.bind.JAXBElement org.tempuri.GetActiveVisasForArrival.travelDocumentNumber
at org.tempuri.GetActiveVisasForArrival
但实际存在对应ObjectFactory,代码如下:
@XmlElementDecl(namespace = "http://tempuri.org/", name = "travelDocumentNumber", scope = GetActiveVisasForArrival.class) public JAXBElement<String> createGetActiveVisasForArrivalTravelDocumentNumber(String value) { return new JAXBElement<String>(_GetActiveVisasForArrivalTravelDocumentNumber_QNAME, String.class, GetActiveVisasForArrival.class, value); }
错误出现在Web服务接口方法的每个参数(XMLGregorianCalendar类型除外)以及所有返回值上。
代码生成配置
<execution> <id>generate-sources</id> <phase>generate-sources</phase> <configuration> <sourceRoot>./generated/cxf</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl>./src/main/resources/wsdl/evisa.wsdl</wsdl> <serviceName>BorderManagementSystemService</serviceName> <extraargs> <extraarg>-client</extraarg> <extraarg>-verbose</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution>
服务初始化代码
service = (IBorderManagementSystemService) new BorderManagementSystemService(new URL(WSDL_LOCATION)).getBasicHttpBindingIBorderManagementSystemService();
该WSDL由C# Web服务提供,尝试过单WSDL选项、从根WSDL生成,问题依旧。
以下几种方案可尝试解决该问题:
1. 添加-autoNameResolution参数到CXF代码生成配置
在<extraargs>中加入该参数,解决JAXB元素命名冲突问题(C#生成的WSDL常存在这类问题):
<extraargs> <extraarg>-client</extraarg> <extraarg>-verbose</extraarg> <extraarg>-autoNameResolution</extraarg> </extraargs>
2. 配置JAXB绑定文件强制识别ObjectFactory
创建jaxb-bindings.xml文件放在资源目录:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="2.1"> <jaxb:globalBindings> <jaxb:serializable uid="1"/> </jaxb:globalBindings> <!-- 绑定目标命名空间 --> <jaxb:bindings schemaLocation="./src/main/resources/wsdl/evisa.xsd" node="/xsd:schema"> <jaxb:schemaBindings> <jaxb:package name="org.tempuri"/> <jaxb:nameXmlTransform> <jaxb:elementName suffix="Element"/> </jaxb:nameXmlTransform> </jaxb:schemaBindings> </jaxb:bindings> </jaxb:bindings>
然后在Maven配置的<wsdlOption>中引用该绑定文件:
<wsdlOption> <wsdl>./src/main/resources/wsdl/evisa.wsdl</wsdl> <serviceName>BorderManagementSystemService</serviceName> <bindingFiles> <bindingFile>./src/main/resources/jaxb-bindings.xml</bindingFile> </bindingFiles> <extraargs> <extraarg>-client</extraarg> <extraarg>-verbose</extraarg> <extraarg>-autoNameResolution</extraarg> </extraargs> </wsdlOption>
3. 校验WSDL命名空间一致性
手动检查WSDL中travelDocumentNumber等元素的命名空间,确保和ObjectFactory中的http://tempuri.org/完全一致,注意大小写、结尾斜杠等细节。
4. 升级CXF版本
CXF 3.4.2存在部分C# WSDL兼容问题,尝试升级到3.5.x或更高稳定版本,这类JAXB元素识别问题可能已被修复。
5. 手动修改生成代码(临时方案)
若以上方案无效,可手动修改生成的GetActiveVisasForArrival类:调整travelDocumentNumber字段的注解,直接引用ObjectFactory中的元素;或去掉JAXBElement包装,直接使用基本类型(需确保WSDL允许该类型直接序列化)。
内容的提问来源于stack exchange,提问作者Serge Iroshnikov

