回调方法执行后JSON反对泽西JAX RS

问题描述:

我使用泽西休息服务与杰克逊API为JSON字符串转换为POJO s转换。需要验证POJO类的所有成员变量。我已经有了用于验证的框架。回调方法执行后JSON反对泽西JAX RS

我想知道的是,如果有任何回调方法或机制可以调用我的验证API发布JSONPOJO转换本身。这样做会使我的工作更轻松,因为我不必在Rest服务类的所有地方调用API。

public class MyPojoClass{ 

    private int interestRateCode; 
    private String name; 

    //just edited 
    private List<TestDTO> testObjs; 

    //Psuedo code 
    //@PostDeserialization 
    public String callbackMethod(Object obj){ 

     if(!ValidationAPI.validate(obj)) 
       return "false"; 
    } 

} 

的TestDTO:

public class TestDTO { 

    private int var1; 
    private String stringVar; 

    public TestDTO() { 
     System.out.println("This constructor does get called every time"); 
    } 
} 

有没有像PostDeserialization任何注解来实现这一目标。这将帮助我使每个POJO类只有一个回调方法进行验证。

我传递的JSON是

{"interestRateCode": 101,"name": "T", 
           "testObjs": [ 
            {"var1" :10, "stringVar": "Arunabh"}, 
            {"var1" :15, "stringVar": "Hejib"} 
           ]} 

任何人谁可以帮助我在这个问题?谢谢你的帮助。

一两件事你可以做的是使用一个Request Filter。在过滤器您可以:

  1. 利用喷射的ResourceInfo
  2. 通过遍历MethodParameter S和检查没有任何注释的方法参数获取实体类获取资源Method。除非使用bean validation,否则在参数旁边使用@Valid,则实体参数始终是没有注释的参数。这是我们如何确定实体参数。从参数中,我们得到这个类。
  3. 从请求中获取实体对象。
  4. 从实体类,从反射使用,找到Method@PostDeserialization注解。
  5. 使用反射调用该方法。

下面是一个完整的测试。 ValidationFilter是前面提到的步骤。

import org.glassfish.jersey.server.ContainerRequest; 
import org.glassfish.jersey.server.ResourceConfig; 
import org.glassfish.jersey.test.JerseyTest; 
import org.junit.Test; 

import javax.ws.rs.Consumes; 
import javax.ws.rs.POST; 
import javax.ws.rs.Path; 
import javax.ws.rs.client.Entity; 
import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import javax.ws.rs.container.ResourceInfo; 
import javax.ws.rs.core.Context; 
import javax.ws.rs.core.Response; 
import javax.ws.rs.ext.ExceptionMapper; 
import java.io.IOException; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.lang.reflect.Parameter; 

import static org.junit.Assert.assertEquals; 

/** 
* Run like any other JUnit test. A couple required dependencies. 
* 
* <dependency> 
* <groupId>org.glassfish.jersey.test-framework.providers</groupId> 
* <artifactId>jersey-test-framework-provider-grizzly2</artifactId> 
* <version>${jersey2.version}</version> 
* <scope>test</scope> 
* </dependency> 
* <dependency> 
* <groupId>org.glassfish.jersey.media</groupId> 
* <artifactId>jersey-media-json-jackson</artifactId> 
* <version>${jersey2.version}</version> 
* </dependency> 
*/ 
public class PostDeserializationTest extends JerseyTest { 

    @Target(ElementType.METHOD) 
    @Retention(RetentionPolicy.RUNTIME) 
    public @interface PostDeserialization {} 


    public static class ValidationError extends RuntimeException { 
     public ValidationError(String message) { 
      super(message); 
     } 
    } 


    public static class ValidationErrorMapper 
      implements ExceptionMapper<ValidationError> { 

     @Override 
     public Response toResponse(ValidationError ex) { 
      return Response.status(Response.Status.BAD_REQUEST) 
        .entity(ex.getMessage()) 
        .build(); 
     } 
    } 


    public static class Bean { 
     public String value; 

     @PostDeserialization 
     public void validate() { 
      if (!"expected".equals(value)) { 
       throw new ValidationError("value must be 'expected'"); 
      } 
     } 
    } 


    public static class ValidationFilter implements ContainerRequestFilter { 

     @Context 
     private ResourceInfo info; 

     @Override 
     public void filter(ContainerRequestContext request) throws IOException { 
      Class<?> entityClass = getEntityClass(); 
      if (entityClass != null) { 
       final ContainerRequest cr = (ContainerRequest) request; 
       cr.bufferEntity(); 
       final Object entity = cr.readEntity(entityClass); 

       findMethodAndValidate(entity); 
      } 
     } 

     private Class<?> getEntityClass() { 
      final Method rm = info.getResourceMethod(); 
      final Annotation[][] paramAnnotations = rm.getParameterAnnotations(); 
      for (int i = 0; i < paramAnnotations.length; i++) { 
       // entity parameters have no annotations. 
       if (paramAnnotations[i].length == 0) { 
        return rm.getParameterTypes()[i]; 
       } 
      } 
      return null; 
     } 

     private void findMethodAndValidate(Object entity) { 
      final Method[] methods = entity.getClass().getMethods(); 
      for (Method method: methods) { 
       if (method.isAnnotationPresent(PostDeserialization.class)) { 
        // validation method should take no parameters. 
        if (method.getParameterCount() != 0) { 
         throw new RuntimeException(
           "Validation method must not have parameters."); 
        } 
        try { 
         method.invoke(entity); 
        } catch (InvocationTargetException ex) { 
         // if an exception happens during invocation, 
         // an InvocationException is thrown. We want the cause, 
         // expecting it to be a ValidationError. 
         Throwable cause = ex.getCause(); 
         if (cause instanceof ValidationError) { 
          throw (ValidationError) cause; 
         } else { 
          throw new RuntimeException(ex); 
         } 
        } catch (Exception ex) { 
         throw new RuntimeException(
           "Error calling validation method.", ex); 
        } 
       } 
      } 
     } 
    } 

    @Path("test") 
    public static class TestResource { 
     @POST 
     @Consumes("application/json") 
     public String post(Bean bean) { 
      return bean.value; 
     } 
    } 

    @Override 
    public ResourceConfig configure() { 
     return new ResourceConfig() 
       .register(TestResource.class) 
       .register(ValidationErrorMapper.class) 
       .register(ValidationFilter.class) 
       .register(new ExceptionMapper<Throwable>() { 
        @Override 
        public Response toResponse(Throwable t) { 
         t.printStackTrace(); 
         return Response.serverError() 
           .entity(t.getMessage()).build(); 
        } 
       }); 
    } 

    @Test 
    public void testValidationError() { 
     final Bean bean = new Bean(); 
     bean.value = "not expected"; 
     final Response response = target("test") 
       .request() 
       .post(Entity.json(bean)); 

     assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); 
     assertEquals("value must be 'expected'", response.readEntity(String.class)); 
    } 

    @Test 
    public void testNoValidationError() { 
     final Bean bean = new Bean(); 
     bean.value = "expected"; 
     final Response response = target("test") 
       .request() 
       .post(Entity.json(bean)); 

     assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); 
     assertEquals("expected", response.readEntity(String.class)); 
    } 
} 
+0

感谢。我会尝试实现这一点。 – Arunabh

+0

我得到java.lang.NoSuchMethodError:java.lang.reflect.Method.getParameters()内getEntityClass()方法。任何想法可能是这个原因。我正在使用Java7。 – Arunabh

+0

我用Java8来摆脱这个错误。不知道我的产品是否允许使用Java 8,那么您可以告诉我如何使它适用于Java7。此外,执行停止在这一行final Object entity = cr.readEntity(entityClass);看起来像这条线有问题,但我没有看到任何堆栈跟踪。 – Arunabh