spring-projects / spring-ws

Spring Web Services
https://spring.io/projects/spring-ws
Apache License 2.0
321 stars 312 forks source link

Support for @WebFault #1392

Open loganmzz opened 11 months ago

loganmzz commented 11 months ago

I have generated classes from WSDL. Fault messages are converted into an Exception with a faultInfo (for detail element) and annoted with @WebFault

When I throw the business exception on server side, it's just converted into a generic javax.xml.ws.soap.SOAPFaultException with just exception message on client side.

Here is my quick&dirty exception resolver:

public class WebFaultAnnotationExceptionResolver implements EndpointExceptionResolver {
    private final ConcurrentMap<Class<?>, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class<?>, JAXBContext>();

    protected Marshaller createMarshaller(Object target) throws JAXBException {
        JAXBContext jaxbContext = jaxbContexts.computeIfAbsent(target.getClass(), clazz -> {
            try {
                return JAXBContext.newInstance(clazz);
            } catch (JAXBException e) {
                throw new RuntimeException(e);
            }
        });
        return jaxbContext.createMarshaller();
    }

    @Override
    public boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex) {
        Annotation webFault = ex.getClass().getAnnotation(WebFault.class);
        if (webFault == null) {
            return false;
        }

        SoapBody soapBody = ((SoapMessage) messageContext.getResponse()).getSoapBody();
        SoapFault soapFault = soapBody.addServerOrReceiverFault(ex.getMessage(), null);

        try {
            Method getFaultInfo = ex.getClass().getMethod("getFaultInfo");
            try {
                Object detail = getFaultInfo.invoke(ex);
                if (detail == null) {
                    return true;
                }
                Marshaller marshaller = createMarshaller(detail);
                marshaller.marshal(detail, soapFault.addFaultDetail().getResult());
                return true;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } catch (NoSuchMethodException e) {
            return true;
        }
    }
}