RESTEasy Mock vs. Exception Mapper vs. Context

RESTEasy mock framework works fine without exception mapper - the request is received, and the object is returned with the expected content.

After registering an exception handler and forcing an exception, the call fails when the internal RESTEasy calls cause ResteasyProviderFactory.getContextData (type), which returns null, which leads to an unexpected error message: "Could not find context data like: javax.servlet.http.HttpServletRequest "

It was not possible to find any examples on the Internet from RESTEasy mock plus an exception display unit, and also could not find anything useful in this error.

Customer 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; } } 

Factory object:

 package com.foo; import javax.xml.bind.annotation.XmlRegistry; @XmlRegistry public class ObjectFactory { public ObjectFactory() { } public Foo createFoo() { return new Foo(); } } 

Check 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 Editor:

 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) 
+6
source share
1 answer

The problem is that the 'mock framework' does not provide an HttpServletRequest for context. It is not directly affiliated with ExceptionMapper .

Resteasy introduces @Context fields based on the data present in ResteasyProviderFactory.getContextDataMap() . When this card does not contain an instance of HttpServletRequest , it explodes with the error "Unable to find context data of type ..."

I worked on this by putting the mock HttpServletRequest in the resteasy context:

 Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); dispatcher.getRegistry().addSingletonResource(new Service()); ResteasyProviderFactory .getContextDataMap() .put(HttpServletRequest.class, new MockHttpServletRequest()); MockHttpResponse response = new MockHttpResponse(); dispatcher.invoke( MockHttpRequest.get("/"), response ); 
+11
source

Source: https://habr.com/ru/post/923821/


All Articles