2012-08-27 27 views
6

Khung công tác RESTEasy hoạt động tốt mà không có người lập bản đồ ngoại lệ - yêu cầu được nhận và thực thể được trả về với nội dung dự kiến.RESTEasy Mock so với Ngoại lệ Mapper so với bối cảnh

Sau khi đăng ký người lập bản đồ ngoại lệ và buộc ngoại lệ, hãy gọi không thành công khi nội bộ của lệnh RESTEasy ResteasyProviderFactory.getContextData (type) trả về null, dẫn đến thông báo lỗi không mong muốn: "Không thể tìm thấy dữ liệu theo ngữ cảnh của loại: javax.servlet. http.HttpServletRequest ".

Không thể tìm thấy bất kỳ ví dụ nào ở bất kỳ nơi nào trực tuyến của mô hình RESTEasy cộng với người lập bản đồ ngoại lệ và cũng không thể tìm thấy bất kỳ điều gì hữu ích về lỗi này.

lớp Chủ đầu tư: Nhà máy

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:

package com.foo; 

import javax.xml.bind.annotation.XmlRegistry; 

@XmlRegistry 
public class ObjectFactory { 

    public ObjectFactory() { 
    } 

    public Foo createFoo() { 
     return new Foo(); 
    } 
} 

Validation ngoại lệ:

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

Dịch vụ thiết bị đầu cuối:

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

Lỗi:

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) 

Trả lời

11

Vấn đề là những 'khuôn khổ giả' không cung cấp một HttpServletRequest với bối cảnh. Nó không liên quan trực tiếp đến ExceptionMapper.

Gây khó chịu @Context trường dựa trên dữ liệu có trong ResteasyProviderFactory.getContextDataMap(). Khi bản đồ này không chứa một thể hiện của HttpServletRequest, nó thổi lên whith lỗi 'Không tìm thấy dữ liệu theo ngữ cảnh của loại ...'

Tôi đã làm việc này bằng cách đặt một giả HttpServletRequest vào bối cảnh resteasy:

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

Cảm ơn bạn đã trả lời! Điều này rất hữu ích. Tôi đã cảm ơn bạn một năm trước, nhưng thông báo qua email đã đi sai địa chỉ email và tôi không thấy bài đăng của bạn cho đến bây giờ. – user1461450

Các vấn đề liên quan