2017-10-11 1 views
0

에서 객체 변환에 JSON을 게시하는 콜백 메소드 JSON 문자열을 POJO으로 변환하기 위해 Jackson API에서 저지 휴식 서비스를 사용하고 있습니다. POJO 클래스의 모든 멤버 변수의 유효성을 검사해야합니다. 이미 유효성 확인을위한 프레임 워크가 있습니다.저지 JAX RS

내가 알고 싶은 것은 유효성 검사 API를 호출 할 수있는 콜백 메소드 또는 메커니즘이 JSON 일 때 POJO 변환 자체에 게시하는 것입니다. 이렇게하면 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"} 
           ]} 

누구인가? 어떤 도움을 주셔서 감사합니다.

답변

0

할 수있는 일은 Request Filter입니다. 당신이하고자 필터에서 :

  1. 는 주입 ResourceInfo
  2. MethodParameter의를 통과하고 주석없이 메서드 매개 변수를 확인하여 엔티티 클래스를 돌려 사용하여 자원 Method를 가져옵니다. bean validation을 사용하지 않는 한 @Valid이 매개 변수 옆에 사용되는 경우 엔티티 매개 변수는 항상 주석이없는 매개 변수입니다. 이것이 엔티티 매개 변수를 결정하는 방법입니다. 매개 변수에서 클래스를 가져옵니다.
  3. 요청에서 엔터티 개체를 가져옵니다.
  4. 리플렉션에서 사용하는 엔티티 클래스에서 @PostDeserialization 주석이있는 Method을 찾으십시오.
  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

getEntityClass() 메소드 내에 java.lang.NoSuchMethodError : java.lang.reflect.Method.getParameters()가 나타납니다. 어떤 아이디어가 이것의 이유가 될 수 있습니다. Java7을 사용하고 있습니다. – Arunabh

+0

Java8을 사용하여이 오류를 제거했습니다. 내 제품이 Java 8 사용을 허용하는지 확실하지 않으므로 Java7에서 작동하도록하는 방법을 알려줄 수 있습니다. 또한이 줄에서 실행이 중지됩니다. Object Object = cr.readEntity (entityClass); 이 줄에는 문제가 있지만 스택 추적에는 아무 것도 표시되지 않습니다. – Arunabh

관련 문제