Groovy 使用自定义注解执行代码

Groovy execute code using custom annotation

我想通过 groovy 脚本中的注释标记执行函数(带参数)。 如果我们使用此注释在 groovy 脚本中执行一个方法,它将在控制台 (stderr) 中打印一条自定义消息,例如:

warning: '<function_name>' is deprecated [[Use '<Deprecated.instead>' instead.][More info: '<Deprecated.more_info>']]

所以,我创建了一个这样的自定义注释

    public @interface Deprecated {
        public String instead() default null
        public String more_info() default null
    }

目标是这样使用它:

def new_call() {
    //new version of the method
}

@Deprecated(instead="new_call")
def call() {
    //do something
}

在我的示例中,它会输出如下:

warning: 'call' is deprecated. Use 'new_call' instead.

我看到了这个 post Groovy: How to call annotated methods,它现在已经 7 年多了,但看起来不错,所以我会看得更深。 我也看到了 Delegate.deprecated 但我不确定这是否是我想要的

我不确定我做得对不对。因此,如果您有任何意见或建议,我将很高兴听到您的意见。

简单的 AOP 方法

这是 very-very 使用 groovy out-of 框的基本实现。

弃用注释

@Target([ElementType.METHOD])
@Retention(RetentionPolicy.RUNTIME)
@interface Deprecated {

    String instead() default 'null'

    String more_info() default 'null'

}

Class 应具有此功能

class 必须实施 GroovyInterceptable - invokeMethod

class SomeClass implements GroovyInterceptable {

    @Override
    def invokeMethod(String name, args) {
        DeprecatedInterception.apply(this, name, args)
    }

    def new_call() {
        println('new_call invoked')
    }

    @Deprecated(instead = 'new_call', more_info = '... the reason')
    def depr_call() {
        println('depr_call invoked')
    }

}

拦截实用程序

import org.codehaus.groovy.reflection.CachedMethod

class DeprecatedInterception {

    static apply(Object owner, String methodName, Object args) {
        MetaMethod metaMethod = owner.metaClass.getMetaMethod(methodName, args)
        Deprecated d = extractAnnotation(metaMethod)
        if (d) {
            println("warning: '$methodName' is deprecated. Use '${d.instead()}' instead. More info: '${d.more_info()}'")
        }
        // handle methods with var-args 
        metaMethod.isVargsMethod() ?
                metaMethod.doMethodInvoke(owner, args) :
                metaMethod.invoke(owner, args)
    }

    static Deprecated extractAnnotation(MetaMethod metaMethod) {
        if (metaMethod instanceof CachedMethod) {
            metaMethod.getCachedMethod()?.getAnnotation(Deprecated)
        } else {
            null
        }
    }

}

简单测试

检查没有exceptions/errors..

class TestWarnings {

    @Test
    void test() {
        new SomeClass().with {
            new_call()
            depr_call()
        }
    }
}

输出:

new_call invoked
warning: 'depr_call' is deprecated. Use 'new_call' instead. More info: '... the reason'
depr_call invoked

免责声明

这应该适用于大多数情况,但有一些限制:

  • 不适用于静态方法(除非在 Object 实例上调用)
  • 您必须为每个 class 实施 GroovyInterceptable,才能申请
  • 您可能在某些 groovy 语法或功能中遇到了一些 side-effects(至少我发现了 vararg 方法调用的问题,但这已经修复)[​​=63=]

因此,在广泛用于某些生产项目之前,应该对其进行测试并可能进行改进。


其他选项:

很快,因为实现可能会更复杂(不确定,至少我不能在短时间内提供一些示例),但这可能更可靠。

  • 添加 AST 转换。
  • 使用一些 AOP 库。