Announcement Announcement Module
No announcement yet.
SoapFault Detail is limited to text strings in SpringWS Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • SoapFault Detail is limited to text strings in SpringWS

    My wsdl operation has a wsdl:fault defined as a complex type. Jaxb generates an object class for it, that can be marshaled.
    I would like springws to add it to, in order to produce a fault message like this:
    <soapenv:Envelope xmlns:soapenv="_2003/05/soap-envelope">
                    <soapenv:Text xml:lang="en-US">NotFoundFaultException</soapenv:Text>
                    <ns2:NotFoundFault xmlns:ns2="_my/server/ws">
    Axis2 client can throw a custom exception mapped to the custom fault then.

    The Detail in soap envelope fault is defined as xs:any in soap-envelope schema.
    Do you plan to support mapping of exceptions to custom complex type soap faults in SpringWS?

  • #2

    I had the same problem, but fortunately Spring-WS allows for customization of generated faults.

    First, my endpoint class (class with @Endpoint annotation) has this method:
       @PayloadRoot(localPart = "query-1", namespace = "")
       public AJAXB2MarshalledResponse query1(AJAXB2MarshalledRequest request) throws AJAXB2MarshalledBusinessException, AJAXB2MarshalledGeneralException
          return this.service.businessMethod(request);
    Then there is a SoapExceptionResolver subclass defined in Spring's context:
       <bean class="">
          <property name="locale">
             <bean class="java.util.Locale">
                <constructor-arg value="pl" />
                <constructor-arg value="PL" />
    Which looks like this:
    public class MyExceptionResolver extends SimpleSoapExceptionResolver
       private Marshaller marshaller;
       /* (non-Javadoc)
        * @see, java.lang.Object, java.lang.Exception,
       protected void customizeFault(MessageContext messageContext, Object endpoint, Exception ex, SoapFault fault)
          if (ex instanceof {
             SoapMessage response = (SoapMessage) messageContext.getResponse();
             Throwable rootEx = ex;
             while (rootEx.getCause() != null)
                rootEx = rootEx.getCause();
             String faultString = StringUtils.hasLength(rootEx.getMessage()) ? rootEx.getMessage() : rootEx.toString();
             SoapBody body = response.getSoapBody();
             fault = body.addClientOrSenderFault(rootEx.getClass().getName(), getLocale());
             fault.getFaultDetail().addFaultDetailElement(new QName("", "error")).addText(faultString);
          try {
             if (ex instanceof AJAXB2MarshalledBusinessException)
                this.marshaller.marshal(((AJAXB2MarshalledBusinessException)ex).getMyJAXB2MarshallableComplexMessage(), fault.getFaultDetail().getResult());
             else if (ex instanceof AJAXB2MarshalledGeneralException)
                fault.getFaultDetail().addFaultDetailElement(new QName("", "error")).addText(((JAXB2MarshalledGeneralException)ex).getMyStringMessage());
             else if (ex instanceof NullPointerException) {
                StringWriter sw = new StringWriter();
                ex.printStackTrace(new PrintWriter(sw));
                fault.getFaultDetail().addFaultDetailElement(new QName("", "error")).addText(sw.toString());
             } else
                fault.getFaultDetail().addFaultDetailElement(new QName("", "error")).addText(ex.toString());
          } catch (Exception e) {
             log.error(e.getMessage(), e);
    Though it doesn't look very simple, it really is - this resolver just deals with five types of exceptions. What you really want is these lines in your exception resolver:
       this.marshaller.marshal(((AJAXB2MarshalledBusinessException)ex).getMyJAXB2MarshallableComplexMessage(), fault.getFaultDetail().getResult());
    When I first saw Spring-WS it seemed lacking some features from Axi2 - particularily server-side method skeletons generated from WSDL's portType's and exceptions.

    First "feature" was only a myth - just look at generated Axis2 skeletons (nightmare) and my simple @Endpoint class with @PayloadRoot (or @SoapAction or WS-A @Action) annotated method. The "second" feature was resolved by the above code.

    A - for completenes, here's my AJAXB2MarshalledBusinessException class:
    public class AJAXB2MarshalledBusinessException extends java.lang.Exception
       private faultMessage;
       public AJAXB2MarshalledBusinessException()
       public AJAXB2MarshalledBusinessException(String message)
       public AJAXB2MarshalledBusinessException(MyJAXB2MarshallableComplexMessage faultMessage)
          this.faultMessage = faultMessage;
       public faultMessage getFaultMessage()
          return this.faultMessage;
       public void setFaultMessage( faultMessage faultMessage)
          this.faultMessage = faultMessage;
    Remember - code generation is double-sided sword. It saves you time at the beginning, but you have to deal with it forever. I don't use code generation in web services - these endpoints and exceptions are not so hard to hand write (though i like JAXB2 generated classes, which I don't have to fine-tune. And one more thing - at project's start everyone has lot of energy, so writing these simple Spring-WS classes is real pleasure

    Grzegorz Grzybek