SpringBoot+Java14 SOAP客户端JAXB序列化失败及绑定文件问题
我刚好碰到过类似的场景,你遇到的问题核心有两个:一是CXF默认不会给WSDL中作为消息参数的complexType生成@XmlRootElement注解,导致Spring OXM序列化失败;二是你写的XPath表达式没有正确定位到WSDL里的complexType节点,因为没考虑WSDL的结构和命名空间。
下面一步步解决:
1. 理解问题根源
当WSDL里的ApprovalRequest和ApprovalResponse是作为<wsdl:message>的参数(比如<wsdl:part type="..." />)时,CXF的wsdl2java默认只会给element对应的类生成@XmlRootElement,而type对应的complexType类不会自动添加这个注解。但Spring的Marshalling组件需要这个注解来识别XML根元素,所以运行时抛出序列化异常。
2. 修正绑定文件的XPath表达式
你之前的XPath//xs:complexType[@name='ApprovalRequest']找不到节点,是因为complexType嵌套在WSDL的<wsdl:types>/<xsd:schema>里,而且需要正确处理命名空间。修改你的BindingFile.xjb如下:
<?xml version="1.0" encoding="UTF-8"?> <jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:annox="http://annox.dev.java.net" jaxb:extensionBindingPrefixes="xjc annox" jaxb:version="2.1"> <!-- 替换成你WSDL中的实际targetNamespace --> <jaxb:bindings schemaLocation="approval.wsdl" node="/wsdl:definitions/wsdl:types/xsd:schema[@targetNamespace='http://travellinck.com/approval']"> <!-- 给ApprovalRequest添加@XmlRootElement --> <jaxb:bindings node="xsd:complexType[@name='ApprovalRequest']"> <annox:annotateClass> <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="ApprovalRequest"/> </annox:annotateClass> </jaxb:bindings> <!-- 给ApprovalResponse添加@XmlRootElement --> <jaxb:bindings node="xsd:complexType[@name='ApprovalResponse']"> <annox:annotateClass> <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="ApprovalResponse"/> </annox:annotateClass> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
重点说明:
- 必须声明
wsdl命名空间,才能定位WSDL结构中的节点 node="/wsdl:definitions/wsdl:types/xsd:schema[@targetNamespace='...']"要精准匹配你的WSDL里的schema节点,替换成实际的targetNamespace- 内层的
node="xsd:complexType[@name='ApprovalRequest']"就能正确找到目标类型了
3. 确保CXF插件配置正确
检查你的cxf-codegen-plugin配置,必须引入jaxb2-basics-annotate依赖,否则-xjc-Xannotate参数不会生效:
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>3.5.5</version> <!-- 选择与你的CXF版本兼容的版本 --> <executions> <execution> <id>generate-soap-client</id> <phase>generate-sources</phase> <configuration> <wsdlOptions> <wsdlOption> <wsdl>${basedir}/src/main/resources/approval.wsdl</wsdl> <bindingFiles> <bindingFile>${basedir}/src/main/resources/BindingFile.xjb</bindingFile> </bindingFiles> <extraargs> <extraarg>-xjc-Xannotate</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.jvnet.jaxb2_commons</groupId> <artifactId>jaxb2-basics-annotate</artifactId> <version>1.1.0</version> </dependency> </dependencies> </plugin>
4. 验证修复效果
执行mvn clean generate-sources,然后查看target/generated-sources/cxf目录下的ApprovalRequest.java和ApprovalResponse.java,应该已经自动添加了@XmlRootElement(name = "ApprovalRequest")注解,此时运行Spring Boot应用,序列化异常应该就消失了。
备选应急方案(不推荐长期使用)
如果绑定文件还是有问题,你可以手动在生成的类上添加@XmlRootElement,但每次执行mvn clean后会被覆盖。所以更好的临时做法是把生成的类拷贝到src/main/java目录下,修改后禁用插件的生成步骤,但这样会导致WSDL更新后无法同步代码,只适合应急。
内容的提问来源于stack exchange,提问作者Richard

