如何从Sitebircks服务自动检索DTO

时间:2015-01-12 09:56:53

标签: java guice interceptor dto sitebricks

是否可以通过sitebricks服务实现automated DTO retrieval这样的方式。

我正在寻找解决方案:

@Post
public Reply<?> post(Request request) {

  DTO dto = request.read(DTO.class).as(Json.class);
  //some dto operations

  .....
  return Reply.saying().ok();
}

可以转换成这样的东西:

@Post
public Reply<?> post(@TransportedBy(Json.class) DTO dto) {

  //some dto operations

  .....
  return Reply.saying().ok();
}

其中@TransoportedBy是自定义注释。

使用这样的技术测试会更容易,因为我不需要模拟Request并期望它的调用。


..........更新..........


在这个阶段,我已经设法实现了如下所用的东西:

@Post
@TransportedBy(Json.class)//any transport can be used
public Reply<?> post(Request request, @Named("DTO") SomeDto dto) {

  //dto must be annotated with @Named("DTO")

  //some dto operations

  .....
  return Reply.saying().ok();
}

我的实现是这样的,但我对它不满意。

注释

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@BindingAnnotation
public @interface TransportedBy {
  Class value();
}

侦听post方法的方法拦截器

public class DtoTransportInterceptor implements MethodInterceptor{


  @Override
  public Object invoke(MethodInvocation methodInvocation) throws Throwable {

    Object[] arguments = methodInvocation.getArguments();
    Method method = methodInvocation.getMethod();
    Annotation[] declaredAnnotations = method.getDeclaredAnnotations();

    //retrieve the request
    Request request = null;
    for(Object argument : arguments){
      if(argument instanceof Request){
        request = (Request) argument;
        break;
      }
    }

    if (request == null) {
      return methodInvocation.proceed();
    }

    //find transport type
    Class transport = null;
    for(Annotation annotation : declaredAnnotations){
      if(annotation instanceof TransportedBy){
        Method m = annotation.getClass().getMethod("value");

        transport = (Class) m.invoke(annotation);
        break;
      }
    }

    if (transport == null){
      return methodInvocation.proceed();
    }

    //get the class type of the dto
    Class dtoClass = null;
    Annotation[][] parametersAnnotations = method.getParameterAnnotations();//all annotations for all parameters
    int dtoParameterId = 0;
    int parameterId = -1;
    for (Annotation[] paramAnnotations : parametersAnnotations){//iterate all parameters and return all annotations for the parameter
      parameterId++;
      for(Annotation annotation : paramAnnotations){//iterate all annotations for a single parameter
        if(annotation instanceof Named){
          Method m = annotation.getClass().getMethod("value");

          String namedValue = (String) m.invoke(annotation);

          if("DTO".equals(namedValue)){
            dtoClass = method.getParameterTypes()[parameterId];
            dtoParameterId = parameterId;
          }
        }
      }
    }

    if(dtoClass == null){
      return methodInvocation.proceed();
    }

    //if the dto is null initialize it and call the method again with the initialized dto, if the dto is not null proceed the method
    if (arguments[dtoParameterId] == null) {
      return method.invoke(methodInvocation.getThis(), request, request.read(dtoClass).as(transport));
    } else {
      return methodInvocation.proceed();
    }
  }
}

绑定拦截器以在这样的guice模块中监听post方法

DtoTransportInterceptor dtoTransportInterceptor = new DtoTransportInterceptor();

bindInterceptor(any(), annotatedWith(Post.class), dtoTransportInterceptor);

由于guice方法拦截器不支持注入,因此仍然需要将请求对象传递给post方法并使用拦截器内的反射进行检索。

这个解决方案并不令人满意,因为我们仍然需要在测试中模拟请求并将其传递给post方法。至少我们不必指望在每个检索dto的测试中调用“request.read(....)”。

我愿意接受其他解决方案。

0 个答案:

没有答案