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
相关产品推荐
相关产品推荐

