是否可以通过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(....)”。
我愿意接受其他解决方案。