Hi, I am using *Dropwizard v1.1.3* with *Java 1.8* to implement a *SOAP Service*. I found that if I raise exceptions in my *SOAP* resource class then these get converted to a *SOAP Fault* message of the form:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <soap:Fault> <faultcode>soap:Server</faultcode> <faultstring>...my error message goes here...</faultstring> </soap:Fault> </soap:Body> </soap:Envelope> This is not an issue as it was what I expected. My *SOAP* resource raises *WebApplicationException* messages which has a facility to also indicate what *HTTP* status code to return to the client, e.g.: throw new WebApplicationException("something went wrong", HttpStatus.SC_UNPROCESSABLE_ENTITY); What I found was that no matter what *HTTP* status code I specify in the *WebApplicationException*, the client always gets a status code of *500*. I therefore thought I'd create my own exception mapper that created a *SOAP Fault* and returned the correct *HTTP* status code. I therefore created this class: public class SoapException extends RuntimeException { private static final long serialVersionUID = 1L; private final int statusCode; public SoapException(final String message, final int statusCode) { super(message); this.statusCode = statusCode; } public int getStatusCode() { return statusCode; } } and changed my exceptions to use this as follows: throw new SoapException("something went wrong", HttpStatus.SC_UNPROCESSABLE_ENTITY); I also created an exception mapper as follows: import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; public class SoapExceptionMapper implements ExceptionMapper<SoapException> { private static final String FAULT_TEMPLATE = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" + " <soap:Body>\n" + " <soap:Fault>\n" + " <faultcode>soap:%s</faultcode>\n" + " <faultstring>%s</faultstring>\n" + " </soap:Fault>\n" + " </soap:Body>\n" + "</soap:Envelope>"; @Override public Response toResponse(final SoapException exception) { final int statusCode = exception.getStatusCode(); final String faultMessage = String.format(FAULT_TEMPLATE, statusCode >= 500 ? "Server" : "Client", exception.getMessage()); return Response.status(statusCode).entity(faultMessage ).type(MediaType.TEXT_XML).build(); } } and registered this mapper in my main application as follows: import com.roskart.dropwizard.jaxws.EndpointBuilder; import com.roskart.dropwizard.jaxws.JAXWSBundle; import io.dropwizard.Application; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; public class MyApp extends Application<MyAppConfiguration> { private static final JAXWSBundle<Object> JAX_WS_BUNDLE = new JAXWSBundle<>("/soap"); public static void main(final String[] args) throws Exception { new MyApp().run(args); } @Override public String getName() { return "my app"; } @Override public void initialize(final Bootstrap<MyAppConfiguration> bootstrap) { bootstrap.addBundle(JAX_WS_BUNDLE); } @Override public void run(final MyAppConfiguration configuration, final Environment environment) { environment.jersey().register(new SoapExceptionMapper()); JAX_WS_BUNDLE.publishEndpoint(new EndpointBuilder("/", new MySoapService(configuration)); } } After doing all this I found that my exception mapper is never invoked. Am I doing something wrong here? Is there a better mechanism for achieving what I want (i.e. have application-specific HTTP status codes returned to the client on errors)? For reference, my SOAP resource implements the following interface: import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.ParameterStyle; import javax.jws.soap.SOAPBinding.Style; import javax.jws.soap.SOAPBinding.Use; @WebService(name="mySoapService", targetNamespace="http://my.app.com") @SOAPBinding(style=Style.DOCUMENT, use=Use.LITERAL, parameterStyle=ParameterStyle.WRAPPED) public interface MySoapService { @WebMethod(operationName="GetStuff", action="http://my.app.com/GetStuff" ) @WebResult(name="Stuff") Stuff getProducts(@WebParam(name="Request") StuffRequest request); } and I see this stack trace when I raise the exception: org.apache.cxf.interceptor.Fault: something went wrong at org.apache.cxf.service.invoker.AbstractInvoker.createFault( AbstractInvoker.java:162) at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.createFault( AbstractJAXWSMethodInvoker.java:267) at org.apache.cxf.service.invoker.AbstractInvoker.invoke( AbstractInvoker.java:128) at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.invoke( AbstractJAXWSMethodInvoker.java:232) at org.apache.cxf.jaxws.JAXWSMethodInvoker.invoke(JAXWSMethodInvoker.java:85 ) at org.apache.cxf.service.invoker.AbstractInvoker.invoke( AbstractInvoker.java:74) at com.roskart.dropwizard.jaxws.ValidatingInvoker.invoke( ValidatingInvoker.java:68) at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run( ServiceInvokerInterceptor.java:59) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at org.apache.cxf.interceptor.ServiceInvokerInterceptor$2.run( ServiceInvokerInterceptor.java:126) at org.apache.cxf.workqueue.SynchronousExecutor.execute( SynchronousExecutor.java:37) at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage( ServiceInvokerInterceptor.java:131) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept( PhaseInterceptorChain.java:308) at org.apache.cxf.transport.ChainInitiationObserver.onMessage( ChainInitiationObserver.java:121) at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke( AbstractHTTPDestination.java:262) at org.apache.cxf.transport.servlet.ServletController.invokeDestination( ServletController.java:234) at org.apache.cxf.transport.servlet.ServletController.invoke( ServletController.java:208) at org.apache.cxf.transport.servlet.ServletController.invoke( ServletController.java:160) at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke( CXFNonSpringServlet.java:180) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest( AbstractHTTPServlet.java:299) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost( AbstractHTTPServlet.java:218) at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service( AbstractHTTPServlet.java:274) at io.dropwizard.jetty.NonblockingServletHolder.handle( NonblockingServletHolder.java:49) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter( ServletHandler.java:1650) at io.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:34 ) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter( ServletHandler.java:1637) at io.dropwizard.jersey.filter.AllowedMethodsFilter.handle( AllowedMethodsFilter.java:50) at io.dropwizard.jersey.filter.AllowedMethodsFilter.doFilter( AllowedMethodsFilter.java:44) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter( ServletHandler.java:1637) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533 ) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle( ScopedHandler.java:188) at org.eclipse.jetty.server.handler.ContextHandler.doHandle( ContextHandler.java:1253) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope( ScopedHandler.java:168) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope( ScopedHandler.java:166) at org.eclipse.jetty.server.handler.ContextHandler.doScope( ContextHandler.java:1155) at org.eclipse.jetty.server.handler.ScopedHandler.handle( ScopedHandler.java:141) at org.eclipse.jetty.server.handler.HandlerWrapper.handle( HandlerWrapper.java:132) at com.codahale.metrics.jetty9.InstrumentedHandler.handle( InstrumentedHandler.java:241) at io.dropwizard.jetty.ContextRoutingHandler.handle( ContextRoutingHandler.java:38) at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle( GzipHandler.java:454) at io.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:68) at org.eclipse.jetty.server.handler.RequestLogHandler.handle( RequestLogHandler.java:56) at org.eclipse.jetty.server.handler.StatisticsHandler.handle( StatisticsHandler.java:169) at org.eclipse.jetty.server.handler.HandlerWrapper.handle( HandlerWrapper.java:132) at org.eclipse.jetty.server.Server.handle(Server.java:564) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317) at org.eclipse.jetty.server.HttpConnection.onFillable( HttpConnection.java:251) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded( AbstractConnection.java:279) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110) at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124) at org.eclipse.jetty.util.thread.Invocable.invokePreferred( Invocable.java:128) at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke( Invocable.java:222) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce( EatWhatYouKill.java:294) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce( EatWhatYouKill.java:126) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob( QueuedThreadPool.java:673) at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run( QueuedThreadPool.java:591) at java.lang.Thread.run(Thread.java:745) ... Thanks in advance. -- You received this message because you are subscribed to the Google Groups "dropwizard-dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to dropwizard-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.