RESTEasy模擬框架可正常工作,無異常映射器 - 接收到請求並返回預期內容的實體。RESTEasy模擬與異常映射器與上下文
註冊異常映射程序並強制執行異常後,當RESTEasy內部調用ResteasyProviderFactory.getContextData(type)時會調用失敗,這會返回null,從而導致意外的錯誤消息:「無法找到類型爲javax.servlet的上下文數據。 http.HttpServletRequest」。
找不到RESTEasy mock加上異常映射程序的任何地方的任何示例,並且找不到有關該錯誤的任何有用內容。
Client類:
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;
}
}
對象工廠:
package com.foo;
import javax.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
}
驗證異常:
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);
}
}
服務端點:
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;
}
}
異常映射:
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();
}
}
測試:
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);
}
}
錯誤:
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)
謝謝回答!這非常有幫助。一年前,我會感謝你,但電子郵件通知發送到了錯誤的電子郵件地址,直到現在我纔看到你的帖子。 – user1461450