Question

I would like to know if it is possible to have an ExceptionMapper handle subclasses of Exception and not just subclasses of RuntimeException?

Take the following code as an example. If the ExampleException extends RuntimeException then the test passes with no errors. However if the ExampleException extends Exception then the test throws an error. See below of the error output.

The following is four classes:

  1. ExampleException
  2. ExampleExceptionMapper
  3. ExampleRest
  4. ExampleRestTest

Here is the code:

public class ExampleException extends Exception {
    public ExampleException(String message) {
    super(message);
    }
}

@Provider
public class ExampleExceptionMapper implements ExceptionMapper<ExampleException> {
    @Override
    public Response toResponse(ExampleException ex) {
        return Response.ok("Exception!").build();
    }
}

@Path("/example")
public class ExampleRest {

    @GET
    @Path(value = "/throw")
    public String throwException() throws ExampleException {
        throw new ExampleException("exception");
    }
}

@EnableServices(value = "jaxrs")
@RunWith(ApplicationComposer.class)
public class ExampleRestTest {

    @Module
    public EjbModule module() {
        EjbJar ejbJar = new EjbJar("beans");
        ejbJar.addEnterpriseBean(new SingletonBean(ExampleRest.class));

        final OpenejbJar openejbJar = new OpenejbJar();
        openejbJar.addEjbDeployment(new EjbDeployment(ejbJar.getEnterpriseBeans()[0]));

        final Properties properties = openejbJar.getEjbDeployment().iterator().next().getProperties();
        properties.setProperty("cxf.jaxrs.providers", ExampleExceptionMapper.class.getName());

        final EjbModule module = new EjbModule(ejbJar);
        module.setOpenejbJar(openejbJar);

        return module;
   }

    @Test
    public void testThrowException() {
        try {
            assertEquals("Exception!", IO.slurp(new URL("http://localhost:4204/ExampleRestTest/example/throw/")));
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }
}

Error Stacktrace:

org.apache.cxf.interceptor.Fault: example.ExampleException: exception: exception while invoking public java.lang.String example.ExampleRest.throwException() throws example.ExampleException with params [].
at org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:166)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:140)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:167)
at org.apache.openejb.server.cxf.rs.OpenEJBEJBInvoker.invoke(OpenEJBEJBInvoker.java:47)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:94)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:58)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:94)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:236)
at org.apache.openejb.server.cxf.rs.CxfRsHttpListener.onMessage(CxfRsHttpListener.java:79)
at org.apache.openejb.server.httpd.OpenEJBHttpRegistry$ClassLoaderHttpListener.onMessage(OpenEJBHttpRegistry.java:99)
at org.apache.openejb.server.httpd.HttpListenerRegistry.onMessage(HttpListenerRegistry.java:69)
at org.apache.openejb.server.httpd.OpenEJBHttpServer.process(OpenEJBHttpServer.java:246)
at org.apache.openejb.server.httpd.OpenEJBHttpServer.processRequest(OpenEJBHttpServer.java:188)
at org.apache.openejb.server.httpd.OpenEJBHttpServer.service(OpenEJBHttpServer.java:103)
at org.apache.openejb.server.httpd.HttpEjbServer.service(HttpEjbServer.java:63)
at org.apache.openejb.server.ServerServiceFilter.service(ServerServiceFilter.java:64)
at org.apache.openejb.server.ServerServiceFilter.service(ServerServiceFilter.java:64)
at org.apache.openejb.server.ServiceStats.service(ServiceStats.java:54)
at org.apache.openejb.server.ServerServiceFilter.service(ServerServiceFilter.java:64)
at org.apache.openejb.server.ServiceLogger.service(ServiceLogger.java:92)
at org.apache.openejb.server.ServerServiceFilter.service(ServerServiceFilter.java:64)
at org.apache.openejb.server.ServicePool.access$201(ServicePool.java:35)
at org.apache.openejb.server.ServicePool$3.run(ServicePool.java:174)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
Was it helpful?

Solution

that's fixed on trunk (https://issues.apache.org/jira/browse/TOMEE-918)

you can workaround it using ExceptionMapper and ex.getCause()

OTHER TIPS

This is soo weak.

Here is a workaround:

import org.apache.openejb.ApplicationException;

/**
 * @FIXME hack for https://issues.apache.org/jira/browse/TOMEE-918
 */
@Provider
public class MyExceptionMapper implements ExceptionMapper<ApplicationException> {  

    @Override 
    public Response toResponse(ApplicationException exception) {
        final Status status;
        final Throwable cause = exception.getCause();

        if (cause instanceof javax.ejb.EJBAccessException)
            status = Status.FORBIDDEN;
         else if (cause instanceof MyException) 
            status = Status.BAD_REQUEST;
         else
            status = Status.INTERNAL_SERVER_ERROR;

        return Response.status(status).entity(cause.getMessage()).build();
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top