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

Spring WS中自定义编组器实现空整数字段反序列化为Null

问题

使用Spring-WS搭建SOAP Web服务时遇到以下场景:

  • 基于不可修改的WSDL生成了ConsultationFibres类,其中offset和limit字段对应WSDL的xsd:int类型,且配置了minOccurs="0"
  • 当SOAP请求中这两个字段为空元素时:
<ns2:offset></ns2:offset>
<ns2:limit></ns2:limit>

反序列化后的值默认是0,但需求是将这类空元素转为null,且不能修改WSDL或生成的类。

已尝试通过javax.xml.bind.annotation.adapters.XmlAdapter定义字符串转整数的规则,但不知道如何覆盖Spring-WS默认使用的编组器/反编组器。

相关配置类代码:

@EnableWs
@Configuration
public class EmutationSOAPConfig extends WsConfigurerAdapter {

    @Autowired
    LoggingInterceptor loggingInterceptor;

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    @Bean(name="emutationService")
    public Wsdl11Definition defaultWsdl11Definition() {
        SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
        wsdl11Definition.setWsdl(new ClassPathResource("/wsdl/emutation-fc1.wsdl"));
        return wsdl11Definition;
    }
// ....
}

端点类代码:

@Endpoint
public class EmutationServiceEndpoint {
    
    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "ConsultationFibres" )
    @ResponsePayload
    public ConsultationFibresResponse consultationFibres(@RequestPayload ConsultationFibres request) throws SoapFaultClientException, EmutationDefaultFaultMessage, EmutationTechnicalFaultMessage {
        ObjectFactory factory = new ObjectFactory();
        ConsultationFibresResponse response =factory.createConsultationFibresResponse();
        // ....
        return response;
    }
}

WSDL中ConsultationFibres的定义片段:

<xsd:element name="ConsultationFibres">
    <xsd:complexType>
        <xsd:sequence>
            <!-- .... -->
            <xsd:element minOccurs="0" name="offset" type="xsd:int"/>
            <xsd:element minOccurs="0" name="limit" type="xsd:int"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:element>

解决方案

1. 实现自定义XmlAdapter处理空值转换

创建适配器类,将空字符串转换为null,非空字符串转为Integer:

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class EmptyStringToNullIntegerAdapter extends XmlAdapter<String, Integer> {
    @Override
    public Integer unmarshal(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // 可选:格式错误时可抛出SOAP Fault或返回null,根据业务需求调整
            return null;
        }
    }

    @Override
    public String marshal(Integer value) {
        return value != null ? value.toString() : null;
    }
}

2. 配置Spring-WS的编组器/反编组器

修改EmutationSOAPConfig类,自定义Jaxb2Marshaller并全局注册上述适配器:

import org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter;
import org.springframework.ws.server.endpoint.adapter.method.PayloadMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.PayloadMethodReturnValueHandler;
import org.springframework.ws.server.endpoint.interceptor.EndpointInterceptor;
import org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping;
import org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver;
import org.springframework.ws.support.MarshallingUtils;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import javax.xml.bind.JAXBContext;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@EnableWs
@Configuration
public class EmutationSOAPConfig extends WsConfigurerAdapter {

    @Autowired
    LoggingInterceptor loggingInterceptor;

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    @Bean(name="emutationService")
    public Wsdl11Definition defaultWsdl11Definition() {
        SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
        wsdl11Definition.setWsdl(new ClassPathResource("/wsdl/emutation-fc1.wsdl"));
        return wsdl11Definition;
    }

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        // 替换为你实际的JAXB生成类所在包
        marshaller.setContextPath("com.your.package.generated");
        
        // 注册自定义适配器
        Map<String, Object> properties = new HashMap<>();
        properties.put(JAXBContextProperties.BEAN_ADAPTERS, 
            Collections.singletonList(new EmptyStringToNullIntegerAdapter()));
        marshaller.setMarshallerProperties(properties);
        marshaller.setUnmarshallerProperties(properties);
        return marshaller;
    }

    // 配置端点适配器,绑定自定义编组器
    @Bean
    public DefaultMethodEndpointAdapter defaultMethodEndpointAdapter() {
        DefaultMethodEndpointAdapter adapter = new DefaultMethodEndpointAdapter();
        adapter.setMethodArgumentResolvers(Collections.singletonList(new PayloadMethodArgumentResolver(marshaller())));
        adapter.setMethodReturnValueHandlers(Collections.singletonList(new PayloadMethodReturnValueHandler(marshaller())));
        return adapter;
    }

    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        interceptors.add(loggingInterceptor);
    }
}

3. 关键说明

  • 务必替换com.your.package.generated为实际的JAXB生成类所在包路径
  • 全局注册适配器后,所有int类型字段遇到空元素都会被转为null,无需修改生成的类
  • 空元素会被JAXB反序列化为空字符串,经过适配器处理后转为null,替代默认的0值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:30:50