title: RESTEasy Mock vs. Exception Mapper vs. Context
body: <p>RESTEasy mock framework works fine without exception mapper--request is received and entity is returned with expected contents.</p>
  
  <p>After registering exception mapper and forcing an exception, call fails when innards of RESTEasy call ResteasyProviderFactory.getContextData(type), which returns null, resulting in unexpected error message: "Unable to find contextual data of type: javax.servlet.http.HttpServletRequest".</p>
  
  <p>Couldn't find any examples anywhere online of RESTEasy mock plus an exception mapper, and couldn't find anything useful about the error either.</p>
  
  <p>Client class:</p>
  
  <pre><code>package com.foo;
  
  import javax.xml.bind.annotation.XmlAccessType;
  import javax.xml.bind.annotation.XmlAccessorType;
  import javax.xml.bind.annotation.XmlRootElement;
  import javax.xml.bind.annotation.XmlType;
  
  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlType(name = "foo-type", propOrder = {
      "name"
  })
  @XmlRootElement(name = "foo")
  public class Foo {
  
      protected String name;
  
      public String getName() {
          return name;
      }
  
      public void setName(String value) {
          this.name = value;
      }
  }
  </code></pre>
  
  <p>Object factory:</p>
  
  <pre><code>package com.foo;
  
  import javax.xml.bind.annotation.XmlRegistry;
  
  @XmlRegistry
  public class ObjectFactory {
  
      public ObjectFactory() {
      }
  
      public Foo createFoo() {
          return new Foo();
      }
  }
  </code></pre>
  
  <p>Validation exception:</p>
  
  <pre><code>package com.foo;
  
  public class ValidationException extends RuntimeException {
  
      private static final long serialVersionUID = -8100360206713223313L;
  
      public ValidationException(String message) {
          super(message);
      }
  
      public ValidationException(Exception innerException) {
          super(innerException);
      }
  
      public ValidationException(String message, Exception innerException) {
          super(message, innerException);
      }
  }
  </code></pre>
  
  <p>Service endpoint:</p>
  
  <pre><code>package com.foo;
  
  import javax.ws.rs.GET;
  import javax.ws.rs.Path;
  import javax.ws.rs.Produces;
  
  @Path("/rest/v1")
  public class FooService {
  
      @GET
      @Path("/foo")
      @Produces("application/xml")
      public Foo alwaysBlowUp() throws ValidationException {
          if (System.currentTimeMillis() &gt; 0) {
              throw new ValidationException("FOO");
          }
          return null;
      }
  }
  </code></pre>
  
  <p>Exception mapper:</p>
  
  <pre><code>package com.foo;
  
  import javax.servlet.http.HttpServletRequest;
  import javax.ws.rs.core.Context;
  import javax.ws.rs.core.HttpHeaders;
  import javax.ws.rs.core.MediaType;
  import javax.ws.rs.core.Response;
  import javax.ws.rs.core.Response.ResponseBuilder;
  import javax.ws.rs.core.Response.Status;
  import javax.ws.rs.ext.ExceptionMapper;
  import javax.ws.rs.ext.Provider;
  
  @Provider
  public class FooExceptionMapper implements ExceptionMapper&lt;ValidationException&gt; {
  
      @Context
      private static HttpServletRequest request;
      @Context
      private static HttpHeaders headers;
  
      @Override
      public Response toResponse(ValidationException exception) {
          MediaType mediaType = null;
  
  /*
  Set breakpoint on line below.
  Step over line and you get the exception in the logs.
  Step into the line and the problem is in ResteasyProviderFactory:
  
  public static &lt;T&gt; T getContextData(Class&lt;T&gt; type)
  {
      return (T) getContextDataMap().get(type); &lt;&lt;&lt; type == javax.servlet.http.HttpServletRequest
  }
  
  The type is not in the map, so it returns null.
  
  The null results in this error in ContextParameterInjector:
  
  private class GenericDelegatingProxy implements InvocationHandler
  {
      public Object invoke(Object o, Method method, Object[] objects) throws Throwable
      {
          try
          {
              Object delegate = ResteasyProviderFactory.getContextData(type);
              if (delegate == null)
                 throw new LoggableFailure("Unable to find contextual data of type: " + type.getName()); &lt;&lt;&lt; ERROR IN LOGS
  */
  
          String acceptHeader = request.getHeader("accept");
  
          if (MediaType.APPLICATION_XML.equals(acceptHeader)) {
              mediaType = MediaType.APPLICATION_XML_TYPE;
          } else if (MediaType.APPLICATION_JSON.equals(acceptHeader)) {
              mediaType = MediaType.APPLICATION_JSON_TYPE;
          } else {
              mediaType = headers.getMediaType();
  
              if (mediaType == null) {
                  mediaType = MediaType.APPLICATION_XML_TYPE;
              }
          }
  
          ResponseBuilder builder = Response.status(Status.BAD_REQUEST);
          builder.type(mediaType);
          return builder.build();
      }
  }
  </code></pre>
  
  <p>Test:</p>
  
  <pre><code>package com.foo;
  
  import java.net.URISyntaxException;
  
  import org.jboss.resteasy.core.Dispatcher;
  import org.jboss.resteasy.mock.MockDispatcherFactory;
  import org.jboss.resteasy.mock.MockHttpRequest;
  import org.jboss.resteasy.mock.MockHttpResponse;
  import org.jboss.resteasy.plugins.server.resourcefactory.POJOResourceFactory;
  
  public final class TestFooExceptionMapper {
  
      public static void main(String[] args) throws URISyntaxException {
          Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
          dispatcher.getRegistry().addResourceFactory(new POJOResourceFactory(FooService.class));
          dispatcher.getProviderFactory().addExceptionMapper(FooExceptionMapper.class);
  
          MockHttpRequest request = MockHttpRequest.get("/rest/v1/foo");
          MockHttpResponse response = new MockHttpResponse();
          dispatcher.invoke(request, response);
      }
  }
  </code></pre>
  
  <p>Error:</p>
  
  <pre><code>Aug 26, 2012 10:44:26 PM org.jboss.resteasy.core.SynchronousDispatcher 
  SEVERE: Failed executing GET /rest/v1/foo
  org.jboss.resteasy.spi.LoggableFailure: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
      at org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy.invoke(ContextParameterInjector.java:56)
      at $Proxy18.getHeader(Unknown Source)
      at com.foo.FooExceptionMapper.toResponse(FooExceptionMapper.java:51)
      at com.foo.FooExceptionMapper.toResponse(FooExceptionMapper.java:1)
      at org.jboss.resteasy.core.SynchronousDispatcher.executeExceptionMapper(SynchronousDispatcher.java:330)
      at org.jboss.resteasy.core.SynchronousDispatcher.unwrapException(SynchronousDispatcher.java:359)
      at org.jboss.resteasy.core.SynchronousDispatcher.handleApplicationException(SynchronousDispatcher.java:348)
      at org.jboss.resteasy.core.SynchronousDispatcher.handleException(SynchronousDispatcher.java:220)
      at org.jboss.resteasy.core.SynchronousDispatcher.handleInvokerException(SynchronousDispatcher.java:196)
      at org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:551)
      at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:513)
      at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:125)
      at com.foo.TestFooExceptionMapper.main(TestFooExceptionMapper.java:20)
  </code></pre>