You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring SOAP客户端中Serializable类型的反序列化报错问题

解决SOAP服务反序列化Serializable类型元素的问题

问题背景

在Spring Boot项目中使用cxf-codegen-plugin的wsdl2java工具生成SOAP服务存根时,接收响应出现反序列化错误。核心问题是WSDL中ValidationResult类型的value字段被定义为ax27:Serializable,但服务实际返回的是包含具体字段的ASNKey对象,导致解析时抛出异常。

相关代码片段

WSDL关键片段

<xs:schema xmlns:ax27="http://io.java/xsd" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://validation.common.services.scope.xxx.com/xsd">
<xs:import namespace="http://io.java/xsd"/>
<xs:complexType name="ValidationResult">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="all" nillable="true" type="ax25:ValidationMessage"/>
<xs:element minOccurs="0" name="value" nillable="true" type="ax27:Serializable"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://io.java/xsd">
<xs:complexType name="Serializable">
<xs:sequence/>
</xs:complexType>
</xs:schema>

pom.xml插件配置

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
                <sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
                <wsdlOptions>
                    <wsdlOption>
                        <wsdl>${basedir}/src/main/resources/MyService.wsdl</wsdl>
                        <wsdlLocation>classpath:MyService.wsdl</wsdlLocation>
                        <bindingFiles>
                            <bindingFile>${basedir}/src/main/resources/binding/bindings.xml</bindingFile>
                        </bindingFiles>
                        <packagenames>
                            <packagename>http://io.java/xsd=com.xxx.io.java.xsd</packagename>
                            <packagename>http://rmi.java/xsd=com.xxx.rmi.java.xsd</packagename>
                        </packagenames>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

绑定文件

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
               jaxb:version="2.0">
    <jaxb:globalBindings generateElementProperty="false" generateIsSetMethod="true" optionalProperty="primitive">
        <xjc:serializable uid="12343"/>
    </jaxb:globalBindings>
</jaxb:bindings>

服务响应示例

<ax25:all type="com.xxx.scope.services.common.validation.ValidationMessage">
    <ax25:code>6100161</ax25:code>
    <ax25:error>true</ax25:error>
    <ax25:info>false</ax25:info>
    <ax25:message>Quantity is required</ax25:message>
    <ax25:objectId/>
    <ax25:objectType/>
    <ax25:type>error</ax25:type>
    <ax25:warning>false</ax25:warning>
</ax25:all>
<ax25:value type="com.xxx.scope.cbo.data.asn.ASNKey">
    <ax21:aaaNumber>PR2406030009</ax21:aaaNumber>
    <ax21:businessUnit>88</ax21:businessUnit>
</ax25:value>

报错信息

Caused by: com.sun.istack.SAXParseException2: unexpected element (uri:"http://aaa.data.cbo.scope.xxx.com/xsd", local:"asnNumber"). Expected elements are (none)

原因分析

  • WSDL中定义的Serializable是一个空的复杂类型,wsdl2java生成的Java类中没有任何字段,无法匹配响应中实际返回的ASNKey结构。
  • 服务端通过类似Java序列化的方式传递对象,但WSDL未正确定义实际类型结构,仅标记为Serializable,导致客户端存根无法解析具体内容。

解决方案

方案1:修改WSDL替换Serializable为实际类型

如果有权限修改WSDL,直接将value字段的类型替换为实际的ASNKey类型,并导入对应的Schema:

<!-- 修改后的ValidationResult -->
<xs:complexType name="ValidationResult">
  <xs:sequence>
    <xs:element maxOccurs="unbounded" minOccurs="0" name="all" nillable="true" type="ax25:ValidationMessage"/>
    <!-- 替换为ASNKey类型 -->
    <xs:element minOccurs="0" name="value" nillable="true" type="ax21:ASNKey"/>
  </xs:sequence>
</xs:complexType>
<!-- 导入ASNKey对应的命名空间Schema -->
<xs:import namespace="http://aaa.data.cbo.scope.xxx.com/xsd"/>

重新生成存根后,ValidationResult类会包含ASNKey类型的value字段,可正常解析响应。

方案2:通过绑定文件映射Serializable到实际类

无法修改WSDL时,通过JAXB绑定文件将ax27:Serializable映射到项目中的ASNKey类:

  1. 确保项目中已存在ASNKey类(可手动创建或通过对应Schema生成)
  2. 修改绑定文件bindings.xml,添加类型映射:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
               jaxb:version="2.0">
    <jaxb:globalBindings generateElementProperty="false" generateIsSetMethod="true" optionalProperty="primitive">
        <xjc:serializable uid="12343"/>
    </jaxb:globalBindings>

    <!-- 将Serializable类型映射到ASNKey类 -->
    <jaxb:bindings schemaLocation="http://io.java/xsd" node="/xs:schema/xs:complexType[@name='Serializable']">
        <jaxb:class name="ASNKey" implClass="com.xxx.scope.cbo.data.asn.ASNKey"/>
    </jaxb:bindings>
</jaxb:bindings>
  1. 执行mvn generate-sources重新生成存根,此时value字段会被映射为ASNKey类型。

方案3:自定义反序列化适配器

若上述方法均不可行,自定义JAXB适配器处理Serializable类型的解析:

  1. 创建适配器类:
public class SerializableAdapter extends XmlAdapter<Object, Serializable> {
    @Override
    public Serializable unmarshal(Object v) throws Exception {
        if (v instanceof Element) {
            Element element = (Element) v;
            ASNKey asnKey = new ASNKey();
            asnKey.setAaaNumber(element.getElementsByTagNameNS("http://aaa.data.cbo.scope.xxx.com/xsd", "aaaNumber").item(0).getTextContent());
            asnKey.setBusinessUnit(Integer.parseInt(element.getElementsByTagNameNS("http://aaa.data.cbo.scope.xxx.com/xsd", "businessUnit").item(0).getTextContent()));
            return asnKey;
        }
        return null;
    }

    @Override
    public Object marshal(Serializable v) throws Exception {
        // 若无需发送该字段,返回null即可
        return null;
    }
}
  1. 在绑定文件中配置适配器:
<jaxb:bindings schemaLocation="http://validation.common.services.scope.xxx.com/xsd" node="/xs:schema/xs:complexType[@name='ValidationResult']/xs:sequence/xs:element[@name='value']">
    <jaxb:property>
        <jaxb:typeAdapters>
            <jaxb:typeAdapter value="com.xxx.adapter.SerializableAdapter"/>
        </jaxb:typeAdapters>
    </jaxb:property>
</jaxb:bindings>

验证

重新编译项目,调用SOAP服务,检查是否能正常接收响应,无反序列化错误抛出。

内容的提问来源于stack exchange,提问作者VeePee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 20:04:51