views:

1452

answers:

2

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?

+3  A: 

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.

Pascal Thivent
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?
waxwing
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...
waxwing
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.
waxwing
A: 

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.

waxwing