2012-08-27 3 views
6

RESTEasy 모의 프레임 워크는 예외 매퍼없이 정상적으로 작동합니다. 요청이 수신되고 예상되는 내용과 함께 엔티티가 반환됩니다.RESTEasy 모의 대 예외 매퍼 대 컨텍스트

예외 매퍼를 등록하고 예외를 강제 실행 한 후 RESTEasy 내부에 ResteasyProviderFactory.getContextData (type) 메서드가 호출되면 null이 반환되어 null이 반환되어 예기치 않은 오류 메시지가 발생합니다. "유형이 javax.servlet 인 문맥 데이터를 찾을 수 없습니다. http.HttpServletRequest ".

RESTEasy mock과 예외 매퍼 중 어떤 곳에서도 예제를 찾을 수 없으며 오류에 대한 유용한 정보도 없습니다.

클라이언트 클래스 :

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) 

답변

11

문제는 '모의 프레임 워크'문맥에 HttpServletRequest을 제공하지 않는다는 것입니다. ExceptionMapper과 직접적인 관련이 없습니다.

@Context 필드는 ResteasyProviderFactory.getContextDataMap()에있는 데이터를 기반으로 입력합니다. 이지도는 HttpServletRequest의 인스턴스를 포함하지 않는 경우, 오류 아 파크 불면 '유형의 상황에 맞는 데이터를 찾을 수 없습니다 ...'

나는 RESTEasy가 컨텍스트에 모의 HttpServletRequest을 넣어이 문제를 해결 일한 :

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 
); 
+1

감사합니다. 이것은 매우 도움이됩니다. 1 년 전에 고맙겠 습니다만 이메일 알림이 잘못된 이메일로 발송되어 지금까지 귀하의 게시물을 보지 못했습니다. – user1461450