2017-10-11 8 views
0

でオブジェクト変換にポストJSONを実行するコールバックメソッドJSON文字列をPOJOに変換するためにジャクソンAPIでジャージーレストサービスを使用しています。 POJOクラスのすべてのメンバー変数を検証する必要があります。私はすでにバリデーションのためのフレームワークを用意しています。ジャージJAX RS

私が知りたいのは、妥当性確認APIを呼び出すことができるコールバックメソッドまたはメカニズムがあり、JSONPOJO変換自体に投稿していることです。これを行うと、私のレストサービスクラスのすべての場所で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クラスに検証のためのコールバックメソッドを1つだけ持たせるのに役立ちます。

私は渡していますJSONは、この問題で私を助けることができる

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

誰もがありますか?助けてくれてありがとう。

答えて

0

あなたができることは、Request Filterを使用することです。あなたが希望フィルターで:

  1. MethodParameter Sを通過し、任意の注釈なしでメソッドのパラメータをチェックすることによって、エンティティクラスを返し注射しResourceInfo
  2. を使用してリソース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の使用が許可されているかどうかわからないので、Java 7で動作させる方法を教えてください。また、実行はこの行で停止します。Object Object = cr.readEntity(entityClass);この行に問題があるように見えますが、スタックトレースには何も表示されません。 – Arunabh