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

JDK17+SpringBoot3.3升级后Apache CXF无法返回自定义检查异常

问题

项目从JDK 11升级到JDK 17+Spring Boot 3.3后,使用Apache CXF(版本4.1.0)调用SOAP Web服务时,服务端抛出的自定义检查异常InputViolationException未被正确转换,客户端收到的是SOAPFaultException。调试发现CXF的ClientFaultConverter未完成转换,partInfo中的类型类名称为null。


相关代码与配置

自定义异常类

@WebFault(name = "InputViolationException", targetNamespace = "http://xmlns.hello.net/serviceException/2_1")
public class InputViolationException extends Exception {
    private com.hello.InputViolationException faultInfo;

    public InputViolationException() {
        super();
    }

    public InputViolationException(String message) {
        super(message);
    }

    public InputViolationException(String message, java.lang.Throwable cause) {
        super(message, cause);
    }

    public InputViolationException(String message, com.hello.InputViolationException inputViolationException) {
        super(message);
        this.faultInfo = inputViolationException;
    }

    public InputViolationException(String message, com.hello.InputViolationException inputViolationException, java.lang.Throwable cause) {
        super(message, cause);
        this.faultInfo = inputViolationException;
    }

    public com.hello.InputViolationException getFaultInfo() {
        return this.faultInfo;
    }
}

CXF依赖与客户端Bean配置

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
    <version>4.1.0</version>
</dependency>
@Bean
public HelloService HelloPort() {
    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
    factory.setWsdlURL(String.valueOf(WSDL_URL));
    factory.setServiceClass(HelloService.class);
    factory.setAddress(baseCcapsUrl);
    SoapInitializer.configureFactory(factory,new SoapInitializer.ConnectionParams(this.connectTimeout, this.requestTimeout), sanitizeXML);
    return (HelloService)factory.create();
}

服务端返回的SOAP响应

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
    <SOAP-ENV:Fault>
        <faultcode>SOAP-ENV:Server</faultcode>
        <faultstring>This is an operation implementation generated fault</faultstring>
        <faultactor/>
        <detail xmlns:ns="http://xmlns.hello.net/serviceException/2_1" xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <ns:InputViolationException>
                <serviceExceptionId>*****</serviceExceptionId>
                <exceptionName>***</exceptionName>
                <originatingComponentName>***</originatingComponentName>
                <detailedMessageText>Error occurred in a component</detailedMessageText>
                <exceptionHandledIndicator>true</exceptionHandledIndicator>
                <serviceExceptionSeverityType>Error</serviceExceptionSeverityType>
                <serviceExceptionType>InputViolationException</serviceExceptionType>
            </ns:InputViolationException>
        </detail>
    </SOAP-ENV:Fault>
</SOAP-ENV:Body></SOAP-ENV:Envelope>

客户端报错堆栈

Caused by: jakarta.xml.ws.soap.SOAPFaultException: This is an operation implementation generated fault
at org.apache.cxf.jaxws.JaxWsClientProxy.mapException(JaxWsClientProxy.java:195)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:145)
at jdk.proxy2/jdk.proxy2.$Proxy60.getEmployeeForADId(Unknown Source)
at com.bmo.channels.docu.adapters.eice.EiceAdapter.getEmployee(EiceAdapter.java:50)
at com.bmo.channels.docu.adapters.eice.EiceAdapterTest.getEmployeeFailure(EiceAdapterTest.java:76)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:76)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
... 25 more
Caused by: org.apache.cxf.binding.soap.SoapFault: This is an operation implementation generated fault
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:87)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:53)

解决方案

针对该问题,可从以下几个方面配置和排查:

  1. 同步WSDL与客户端异常定义

    • 检查WSDL中InputViolationException的fault定义,确保命名空间http://xmlns.hello.net/serviceException/2_1、元素结构与客户端faultInfo类完全匹配。
    • 升级环境后建议重新通过wsdl2java生成客户端代码,避免版本兼容导致的代码不一致问题。
  2. 自定义CXF异常转换器
    实现自定义ClientFaultConverter,手动解析SOAP Fault的detail节点并转换为目标异常:

    public class CustomFaultConverter extends ClientFaultConverter {
        @Override
        public Exception convertFault(Message message, Throwable ex) {
            SoapFault soapFault = (SoapFault) ex;
            Element detailElement = soapFault.getDetail();
            if (detailElement != null) {
                Node faultNode = detailElement.getElementsByTagNameNS("http://xmlns.hello.net/serviceException/2_1", "InputViolationException").item(0);
                if (faultNode != null) {
                    try {
                        JAXBContext context = JAXBContext.newInstance(com.hello.InputViolationException.class);
                        com.hello.InputViolationException faultInfo = (com.hello.InputViolationException) context.createUnmarshaller().unmarshal(faultNode);
                        return new InputViolationException(soapFault.getMessage(), faultInfo, soapFault);
                    } catch (JAXBException e) {
                        return super.convertFault(message, ex);
                    }
                }
            }
            return super.convertFault(message, ex);
        }
    }
    

    将转换器注册到客户端工厂:

    @Bean
    public HelloService HelloPort() {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setWsdlURL(String.valueOf(WSDL_URL));
        factory.setServiceClass(HelloService.class);
        factory.setAddress(baseCcapsUrl);
        // 注册自定义异常转换器
        factory.getInInterceptors().add(new ClientFaultInterceptor(new CustomFaultConverter()));
        SoapInitializer.configureFactory(factory,new SoapInitializer.ConnectionParams(this.connectTimeout, this.requestTimeout), sanitizeXML);
        return (HelloService)factory.create();
    }
    
  3. 验证CXF与Spring Boot兼容性

    • CXF 4.1.0兼容Spring Boot 3.x,但可尝试升级到CXF最新稳定版本(如4.1.x后续版本),修复已知的异常转换bug。
  4. 确认JAXB依赖配置
    Spring Boot 3.x使用Jakarta EE API,确保已引入JAXB相关依赖:

    <dependency>
        <groupId>jakarta.xml.bind</groupId>
        <artifactId>jakarta.xml.bind-api</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <scope>runtime</scope>
    </dependency>
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 16:25:58