2

有没有什么方法可以实现像这样的自动 DTO 检索,但需要使用 sitebricks 服务。

我正在寻找以下解决方案:

@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 是自定义注释。

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


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


在这个阶段,我已经设法实现了一些类似的东西:

@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(....)”。

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

4

0 回答 0