Search code examples
javaweb-servicessoapcxfbean-validation

Apache CXF bean validation fault details


I'm trying to use BeanValidation feature of Apache CXF. And stuck now cause don't have any clue how to handle and parse exceptions thrown by validator. I have web-service interface:

@WebService
@SOAPBinding(style=SOAPBinding.Style.DOCUMENT, use=SOAPBinding.Use.LITERAL, parameterStyle=SOAPBinding.ParameterStyle.BARE)
public interface TestWSInterface {
    @WebMethod
    @WebResult(name = "helloResponse")
    @Valid
    public Hello.Response hello(@WebParam(name = "helloRequest") @Valid Hello.Request request) throws TestWSException;
}

Hello.Request is annotated:

@XmlType(name = "HelloRequest")
public static class Request extends Command.Request {

    @NotNull(message = "not null required")
    @Size(min = 1, max = 5, message = "[1..5] characters")
    public String name;
}

And following configuration in cfx-servlet.xml:

<jaxws:endpoint id="testWS" implementor="#test" address="/TestWS">
    <jaxws:features>
        <ref bean="commonValidationFeature"/>
    </jaxws:features>
</jaxws:endpoint>
<bean id="commonValidationFeature" class="org.apache.cxf.validation.BeanValidationFeature"/>

So, then I run my request with SoapUI and pass name containing for example 6 characters, I have following response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <soap:Fault>
            <faultcode>soap:Server</faultcode>
            <faultstring>Fault occurred while processing.</faultstring>
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

So my main question is - How can I catch ConstraintViolationException and extend resulting fault response with detailed messages from annotation constraint? Documentation from Apache CXF - Bean Validation Feature looks not very helpful for me. So I really in need for example.


Solution

  • I am facing the same issue and I fixed it using AbstractSoapInterceptor. To register your Custom Interceptor you have to add the following annotation to your web service.

    @OutFaultInterceptors(interceptors = { "com.saqi.config.FaultInterceptor" })
    

    After that, you have to write your custom FaultInterceptor as follows.

    public class FaultInterceptor extends AbstractSoapInterceptor {
    
        public FaultInterceptor() {
            super(Phase.MARSHAL);
        }
    
        @Override
        public void handleMessage(SoapMessage soapMessage) throws Fault {
            Fault fault = (Fault) soapMessage.getContent(Exception.class);
    
            if (fault.getCause() != null && fault.getCause() instanceof ConstraintViolationException) {
    
                ConstraintViolationException constraintViolationException = (ConstraintViolationException) fault.getCause();
    
                if (!constraintViolationException.getConstraintViolations().isEmpty()) {
                    Set<ConstraintViolation<?>> constraintViolations = constraintViolationException
                            .getConstraintViolations();
    
                    for (ConstraintViolation constraintViolation : constraintViolations) {
                        fault.setMessage(constraintViolation.getMessage());
                    }
                }
            }
        }
    }
    

    This will show your ConstraintViolationException messages as follows.

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
       <soap:Body>
          <soap:Fault>
             <faultcode>soap:Server</faultcode>
             <faultstring>Id should follow the pattern!</faultstring>
          </soap:Fault>
       </soap:Body>
    </soap:Envelope>
    

    Note: I am using cxf version 3.1.6