Java 我们可以传递方法参数的值和注释吗

Java 我们可以传递方法参数的值和注释吗,java,reflection,rest-assured,Java,Reflection,Rest Assured,为了管理招摇过市的文档,我正在为调用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

为了管理招摇过市的文档,我正在为调用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();
}
private SwagRef defineSwaggerInfo(){
List stackTrace=asList(currentThread().getStackTrace());
返回stackTrace.stream()
.map(tryOrNull(element->Pair.with(element.getMethodName()、forName(element.getClassName()))
.filter(对象::非空)
.filter(pair->MyAPI.class.isAssignableFrom(pair.getValue1())
.map(pair->with(pair.getValue0(),asList(pair.getValue1().getDeclaredMethods()))
.平面图(
tryOrNull(
配对->
pair.getValue1().stream()
.filter(方法->对象.equals(方法.getName(),对.getValue0())
.peek(方法->方法.setAccessible(true))
.map(方法->方法.getAnnotation(SwagRef.class)))
.filter(对象::非空)
.findFirst()
.orelsetrow();
}
但是,我无法提供使用方法参数构建请求规范的通用函数


我尝试查看AspectJ,但无法正确嵌入它

无法通过反射从堆栈中获取实际参数值。事实上,甚至不能保证正在进行的调用的参数值仍在堆栈上

要执行自动参数处理,最接近的方法是在接口中声明方法并生成:


或者,您可以在接口和可能是非公共的助手类之间拆分逻辑。

无法通过反射从堆栈获取实际参数值。事实上,甚至不能保证正在进行的调用的参数值仍在堆栈上

要执行自动参数处理,最接近的方法是在接口中声明方法并生成:


或者,您可以在接口和一个可能是非公共的助手类之间分割逻辑。

您可以用真实代码替换伪代码,显示如何从
getStackTrace()
调用
getAnnotation(SwagRef.class)
打开它吗?当然可以,但这只是指我能做的事情。我能够从带注释的方法中获取url和方法ref,因为它是常量,但是当调用函数以可能创建一个通用的RequestSpecification BuilderWell时,我无法通过参数的注释传递和获取参数的值,看到实际代码有助于理解您在做什么。请注意,1)当存在多个同名方法时,您的代码可能会以错误的方法结束,2)
setAccessible(true)
已过时3)而不是
.map(method->method.getAnnotation(SwagRef.class))
您可能想使用
过滤器(method->method.hasnotation(SwagRef.class)))
若要保留
方法
对象,您将无法访问
@MyParam
注释4)如果“参数”指的是实际参数值,但无法通过ReflectionTanks获得,我知道此代码有多个函数名的缺点,为此,我们将维护代码,使其只在实际调用API的函数上具有注释,而不是重载方法。是的,过滤器部分是一个很好的建议,你应该这样做。你能用真实的代码替换伪代码吗?显示你如何从
getStackTrace()
到你可以调用
getAnnotation(SwagRef.class)
的东西?当然,但这只是参考我能做的。我能够从带注释的方法中获取url和方法ref,因为它是常量,但是当调用函数以可能创建一个通用的RequestSpecification BuilderWell时,我无法通过参数的注释传递和获取参数的值,看到实际代码有助于理解您在做什么。请注意,1)当存在多个同名方法时,您的代码可能会以错误的方法结束,2)
setAccessible(true)
已过时3)而不是
.map(method->method.getAnnotation(SwagRef.class))
您可能想使用
过滤器(method->method.hasnotation(SwagRef.class)))
若要保留
方法
对象,您将无法访问
@MyParam
注释4)如果“参数”指的是实际参数值,但无法通过ReflectionTanks获得,我知道此代码有多个函数名的缺点,为此,我们将维护代码,使其只在实际调用API的函数上具有注释,而不是重载方法。是的,过滤器部分是一个很好的建议,应该这样做。这绝对像魅力一样工作,但有一个缺点。这样,我只能通过初始化的代理接口调用callMyAPI,这就阻止了我将其插入到包含API方法的类的层次结构中。这需要一些重构来弥合这一差距。你认为在任何带注释的方法上使用AspectJ都可以做些什么吗?我没有使用AspectJ的经验,但我可以想象它有一些帮助
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);
}
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;
    }
}