要管理庞大的文档,我对调用API的方法使用了自定义注释
@SwagRef(method = POST, url = "/my/api/{pathParam1}")
public Response callMyAPI(
@MyParam(name = "pathParam1", required = true, in = PATH) String p1,
@MyParam(name = "param2", required = false, in = QUERY) String p2) {
return given()
.pathParam("pathParam1", p1)
.queryParam("param2", p2)
.get();
}
有另一段代码可以验证Swagger / api / docs与注释。 但是,我想知道是否有可能在批注中使用所有这些已经呈现的数据,并拥有一个通用代码,可以在其中传递方法引用或参数引用,并可以使用批注构建RequestSpecification。
我尝试了反射,但是我无法使用方法中的反射来获取参数的值
我只能推断方法类型和API,因为它使用methodName和stackTrace保持不变
private SwagRef defineSwaggerInfo() {
List<StackTraceElement> stackTrace = asList(currentThread().getStackTrace());
return stackTrace.stream()
.map(tryOrNull(element -> Pair.with(element.getMethodName(), forName(element.getClassName()))))
.filter(Objects::nonNull)
.filter(pair -> MyAPI.class.isAssignableFrom(pair.getValue1()))
.map(pair -> with(pair.getValue0(), asList(pair.getValue1().getDeclaredMethods())))
.flatMap(
tryOrNull(
pair ->
pair.getValue1().stream()
.filter(method -> Objects.equals(method.getName(), pair.getValue0()))
.peek(method -> method.setAccessible(true))
.map(method -> method.getAnnotation(SwagRef.class))))
.filter(Objects::nonNull)
.findFirst()
.orElseThrow();
}
但是我无法使用泛型函数来使用方法参数来构建请求规范
我尝试查看AspectJ,但无法正确嵌入
答案 0 :(得分:2)
无法通过反射从堆栈中获取实际参数值。实际上,甚至没有保证在那一点上正在进行的调用的参数值仍在堆栈中。
执行自动参数处理最接近的方法是在接口中声明方法并生成proxy:
interface FrontEnd {
public static FrontEnd get() {
return (FrontEnd)Proxy.newProxyInstance(FrontEnd.class.getClassLoader(),
new Class<?>[]{FrontEnd.class}, (proxy, method, args) -> {
if(method.getDeclaringClass() == Object.class) {
switch(method.getName()) {
case "toString": return
FrontEnd.class.getName()+'@'+System.identityHashCode(proxy);
case "equals": return proxy == args[0];
case "hashCode": return System.identityHashCode(proxy);
default: throw new AssertionError();
}
}
SwagRef swagRef = method.getAnnotation(SwagRef.class);
if(swagRef == null) throw new IncompatibleClassChangeError();
MyParam[] p = Arrays.stream(method.getParameterAnnotations())
.map(pa -> Arrays.stream(pa)
.filter(a -> a.annotationType() == MyParam.class)
.findFirst().orElseThrow(
() -> new IllegalStateException("missing required @MyParam")))
.toArray(MyParam[]::new);
Map<String,String> map = IntStream.range(0, args.length).boxed()
.filter(i -> p[i].required() || args[i] != null)
.collect(Collectors.toMap(i -> p[i].name(), i -> args[i].toString()));
// do actual invocation logic here
System.out.println(
"operation: "+swagRef.method()+' '+swagRef.url()+", "+map);
return null;
});
}
@SwagRef(method = POST, url = "/my/api/{pathParam1}")
public Response callMyAPI(
@MyParam(name = "pathParam1", required = true, in = PATH) String p1,
@MyParam(name = "param2", required = false, in = QUERY) String p2);
}
您可以向该接口添加更多方法,以相同的方式处理,前提是它们都具有必要的注释。
从Java 9开始,您可以在private
中使用interface
方法,在这里我更喜欢。
interface FrontEnd {
public static FrontEnd get() {
return (FrontEnd)Proxy.newProxyInstance(FrontEnd.class.getClassLoader(),
new Class<?>[]{FrontEnd.class}, FrontEnd::callImpl);
}
@SwagRef(method = POST, url = "/my/api/{pathParam1}")
public Response callMyAPI(
@MyParam(name = "pathParam1", required = true, in = PATH) String p1,
@MyParam(name = "param2", required = false, in = QUERY) String p2);
private static Object callImpl(Object proxy, Method method, Object[] args) {
if(method.getDeclaringClass() == Object.class) {
switch(method.getName()) {
case "toString": return
FrontEnd.class.getName()+'@'+System.identityHashCode(proxy);
case "equals": return proxy == args[0];
case "hashCode": return System.identityHashCode(proxy);
default: throw new AssertionError();
}
}
SwagRef swagRef = method.getAnnotation(SwagRef.class);
if(swagRef == null) throw new IncompatibleClassChangeError();
MyParam[] p = Arrays.stream(method.getParameterAnnotations())
.map(pa -> Arrays.stream(pa)
.filter(a -> a.annotationType() == MyParam.class)
.findFirst().orElseThrow(
() -> new IllegalStateException("missing required @MyParam")))
.toArray(MyParam[]::new);
Map<String,String> map = IntStream.range(0, args.length).boxed()
.filter(i -> p[i].required() || args[i] != null)
.collect(Collectors.toMap(i -> p[i].name(), i -> args[i].toString()));
// do actual invocation logic here
System.out.println("operation: "+swagRef.method()+' '+swagRef.url()+", "+map);
return null;
}
}
或者,您可以在接口和一个可能是非公共的帮助程序类之间拆分逻辑。