JAX-WS - Map Exceptions to faults
Asked Answered
D

2

29

I am using JAX WS to expose a WebService. Some of the operations of this service can generate exceptions. Not internal server exceptions, but rather exceptions that are dependent on the input arguments of the operation invocation.

If I specify that my operation throws a custom Exception, like so:

@WebService
@SOAPBinding(style = Style.RPC, use = Use.LITERAL)
public class MyServiceEndpointImpl implements MyServiceEndpoint {

    @WebMethod
    public void throwsException throws InvalidInputException;
}

I end up with the following stacktrace when running the application:

 com.sun.xml.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class com.mypackage.ws.services.jaxws.InvalidInputExceptionBean is not found. Have you run APT to generate them?
    at com.sun.xml.ws.model.RuntimeModeler.getClass(RuntimeModeler.java:285)
    at com.sun.xml.ws.model.RuntimeModeler.processExceptions(RuntimeModeler.java:1006)
    at com.sun.xml.ws.model.RuntimeModeler.processRpcMethod(RuntimeModeler.java:969)
    at com.sun.xml.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:546)
    at com.sun.xml.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:370)
    at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:256)
    at com.sun.xml.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:322)
    at com.sun.xml.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:188)
    at com.sun.xml.ws.api.server.WSEndpoint.create(WSEndpoint.java:467)
    at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:333)
    at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:45)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:121)

Adding @XmlRootEntity to InvalidInputException does not solve the problem.

If this is not the recommended way to report faults over web services, then is there a better way? Should my exceptions inherit from RuntimeException and rely on the transport for the error handling (i.e., everything will end up wrapped in a SOAPException)? I was hoping for something like Spring-WS' SoapFaultAnnotationExceptionResolver. Is there something similar at all available for JAX-WS?

Darcydarda answered 14/1, 2010 at 13:45 Comment(1)
Perhaps I should note that the class it reports as missing, com.mypackage.ws.services.jaxws.InvalidInputExceptionBean, indeed does not exist. But I assumed that was natural, that it should be generated like the exception states.Darcydarda
A
28

Did you try to annotate your exception with @WebFault? Also, do you implement getFaultInfo()?

EDIT: I realize my answer was maybe not detailed enough. As reminded in this thread (for example):

The JAX-WS 2.0 specification demands that the exception annotated with @WebFault must have two constructors and one method [getter to obtain the fault information]:

WrapperException(String message, FaultBean faultInfo)
WrapperException(String message, FaultBean faultInfo, Throwable cause)
FaultBean getFaultInfo()

The WrapperException is replaced by the name of the exception, and FaultBean is replaced by the class name that implements the fault bean. The fault bean is a Java bean that contains the information of the fault and is used by the Web service client to know the cause for the fault.

This is detailed in section 2.5 Fault of the JAX-WS specification. Does your exception conform to this? Can you post the code?


The OP is right. As per specification 2.1, section 3.7 Service Specific Exception, it is not required to use the @WebFault annotation, JAX-WS can generate the wrapper beans dynamically for exceptions that do not match the pattern described in section 2.5 (just provide a getter for the information you want to be present in the fault). For exceptions that match the pattern described in section 2.5 (i.e. exceptions that have a getFaultInfo method and @WebFault annotation), the FaultBean is used as input to JAXB when mapping the exception to XML Schema.

So the solution suggested above (matching the pattern described in section 2.5) is only a workaround. The generation of wrapper beans should just work for other exceptions. And I don't know why this fails here.

Amphiboly answered 14/1, 2010 at 14:22 Comment(5)
I did not. I tried that now, but I get the same error. But do I need to specify @WebFault's properties name, targetNameSpace and faultBean as well?Darcydarda
Thanks for the hint, I will look into it. No, I did not implement the constructors you indicated. I read (misread?) that part of the specification as the JAX WS implementation would automatically generate the exception wrapper itself with those constructors. I am beginning to think I am doing something backwards...Darcydarda
It turns out that conforming to the Exception style you wrote above means that JAX-WS will not create a wrapper bean for the exception, which it otherwise should. So that works as a workaround for me. However, it should work with all exceptions without annotations, according to "3.7 Service Specific Exception" in the spec.Darcydarda
@Pascal Thivent - Everytime I look for an answer I find you. Maybe I should just resign and you can do my job? :)Incarnate
@PascalThivent : it seems that even in JAX-WS 2.0 the getFaultInfo was optional. At the end of section 3.7 the same sample mapping can be found as in spec version 2.1. It doesn't seem widely supported though.Photina
D
17

An addition to the answer above. I ended up with this as my InvalidInputException implementation:

@WebFault(faultBean = "com.mypackage.ws.exception.FaultBean")
public class InvalidInputException extends Exception {

    private static final long serialVersionUID = 1L;

    private FaultBean faultBean;

    public InvalidInputException() {
        super();
    }

    public InvalidInputException(String message, FaultBean faultBean, Throwable cause) {
        super(message, cause);
        this.faultBean = faultBean;
    }

    public InvalidInputException(String message, FaultBean faultBean) {
        super(message);
        this.faultBean = faultBean;
    }

    public FaultBean getFaultInfo() {
        return faultBean;
    }
}

And FaultBean is just a simple POJO with currently no data at all. Now, according to the JAX-WS specification (see 3.7 Service Specific Exception), it conforms to what is required of an exception annotated with @WebFault, so it will not create a wrapper bean for it, which probably is what was failing.

This is a decent workaround, but it does not explain the error in the question.

Darcydarda answered 14/1, 2010 at 17:10 Comment(3)
+1 for this, it saved my day :). But this is only working for checked Exceptions not for unchecked Exceptions. Any clues...Measureless
@Darcydarda I have implemented an example however my example doesn't work without defining targetNamespace element?Corina
@rits Well same happened to me I tried this on Websphere 8.5.5 which has Axis 2 as a service provider for JAX-WS and it didn't work with RuntimeException, but it did work doing the same with Websphere Liberty Profile because it uses Apache CXF instead. It's a shame actually because now my client need to catch/declare the exception.Highflown

© 2022 - 2024 — McMap. All rights reserved.