The response to this wasn’t exactly overwhelming. One email said the mock
framework is going to be deprecrated, which is fine, but in the meantime it
would be good to find the cause of this.
A few minor changes to show that it’s tied to the exception:
package com.foo;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("/rest/v1")
public class FooService {
public static boolean BLOW_UP = false;
@GET
@Path("/foo")
@Produces({"application/xml"})
public Foo doFoo() throws FooValidationException {
if (BLOW_UP) {
throw new FooValidationException("FOO");
}
Foo foo = new Foo();
foo.setName("FOO");
return foo;
}
}
package com.foo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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,
UnsupportedEncodingException, IOException {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addResourceFactory(new
POJOResourceFactory(FooService.class));
dispatcher.getProviderFactory().addExceptionMapper(FooExceptionMapper.class);
MockHttpRequest request;
MockHttpResponse response;
System.out.println("Test without exception:");
request = MockHttpRequest.get("/rest/v1/foo");
response = new MockHttpResponse();
dispatcher.invoke(request, response);
System.out.println(new
String(((ByteArrayOutputStream)response.getOutputStream()).toByteArray(),
"UTF-8"));
System.out.println();
System.out.println("Test with exception:");
request = MockHttpRequest.get("/rest/v1/foo");
response = new MockHttpResponse();
FooService.BLOW_UP = true;
dispatcher.invoke(request, response);
System.out.println(new
String(((ByteArrayOutputStream)response.getOutputStream()).toByteArray(),
"UTF-8"));
}
}
Test without exception:
<?xml version="1.0" encoding="UTF-8"
standalone="yes"?><foo><name>FOO</name></foo>
Test with exception:
Sep 03, 2012 2:34:37 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:50)
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:35)
At the point where it blows up, it’s trying to get contextual data for
HttpServletRequest.
Why is it doing that when the type of mock request sent in is a subclass of
HttpRequest? Where does it get confused about the appropriate type to be
looking up? This seems like a bug.
I thought about changing our POM to download resteasy-jaxrs-beta1.jar, which
has a MockHttpServletRequest, but then our test configuration differs from our
runtime configuration in too many ways.
Sent: Monday, August 27, 2012 9:42 AM
To: resteasy-users@lists.sourceforge.net
Subject: [Resteasy-users] Problem using RESTEasy mock framework withexception
mapper
RESTEasy mock framework works fine without exception mapper--request is
received and entity is returned with expected contents.
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".
Couldn't find any examples anywhere online of RESTEasy mock plus an exception
mapper, and couldn't find anything useful about the error either.
Client class:
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;
}
}
Object factory:
package com.foo;
import javax.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
}
Validation exception:
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);
}
}
Service endpoint:
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() > 0) {
throw new ValidationException("FOO");
}
return null;
}
}
Exception mapper:
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<ValidationException> {
@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 <T> T getContextData(Class<T> type)
{
return (T) getContextDataMap().get(type); <<< 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()); <<< 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();
}
}
Test:
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);
}
}
Error:
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)
http://stackoverflow.com/questions/12136780/resteasy-mock-vs-exception-mapper-vs-context
--------------------------------------------------------------------------------
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
--------------------------------------------------------------------------------
_______________________________________________
Resteasy-users mailing list
Resteasy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/resteasy-users
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Resteasy-users mailing list
Resteasy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/resteasy-users