【问题标题】:Is there a way to inherit interface method annotation in Groovy? (possible glitch in @Delegate)有没有办法在 Groovy 中继承接口方法注解? (@Delegate 中可能出现故障)
【发布时间】:2015-08-31 00:33:21
【问题描述】:

我的示例是使用 Koshuke args4j's @Option 注释完成的,但同样适用于任何其他方法注释。澄清一下,这个注解可以与字段或设置器一起使用。

它的工作原理如下:

class AnOptionExample {
    @Option(name = '-text')
    String text
}

还有测试用例:

def 'recognises option from simple object'() {
    given:
    def options = new AnOptionExample()
    def parser = new CmdLineParser(options)

    when:
    parser.parseArgument('-text=whatever')

    then:
    options.text == 'whatever'
}

现在假设我想在接口级别进行注释,然后重新使用 @Option 定义以及具有多种继承,这将允许为不同的选项集使用不同的接口(简化示例) :

interface Credentials {
    @Option(name = '-username')
    void setUsername(String username)

    @Option(name = '-password')
    void setPassword(String username)

    String getUsername()

    String getPassword()
}

class CredentialsImpl implements Credentials {
    String username
    String password
}

显示失败的测试用例:

def 'does not recognise option from interface'() {
    given:
    def options = new CredentialsImpl()
    def parser = new CmdLineParser(options)

    when:
    parser.parseArgument('-username=John', '-password=qwerty123')

    then:
    def ex = thrown(CmdLineException)
    ex.message == '"-username=John" is not a valid option'
}

嗯,接口的方法注解是不会被继承的。很公平——这就是 Java 的方式,但是 Groovy 呢?以下是一些希望:

class SomeOptionsWithDelegate {
    @Delegate(methodAnnotations = true)
    final Credentials credentials = new CredentialsImpl()

    @Option(name = '-url')
    String url
}

还有显示一些奇怪的测试用例:

def 'does recognise option from interface via @Delegate'() {
    given:
    def options = new SomeOptionsWithDelegate()
    def parser = new CmdLineParser(options)

    when:
    parser.parseArgument('-username=John', '-password=qwerty123', '-url=http://auth.plop.com')

    then:
    with(options) {
        username == 'John'
        password == 'qwerty123'
        url == 'http://auth.plop.com'
    }
}

令人惊讶的是@Delegate(methodAnnotations = true) 工作,尽管委托完成的对象实例没有注释 - 只有Credentials 接口有它们。并且没有方法注释继承......哦等等,实际上这就是重点。这似乎是一个小故障。如果CredentialsImpl没有继承接口级别的那些注解,为什么@Delegate能够拾取这些注解?

另一方面,我希望将这样的行为作为一个特性,所以我不需要在这里使用委托,而是像这样:

@InheritInterfaceMethodAnnotations
class SomeOptionsViaInterface implements Credentials {
    String username
    String password

    @Option(name = '-url')
    String url
}

上述示例的明显相关测试用例会以与第二个示例相同的方式失败。因此问题是:有没有像我虚构的注释一样的东西 - @InheritInterfaceMethodAnnotations 可用? 考虑到@Delegate 故障,可以实现。由于它似乎是有用的功能,也许有人已经做到了。如果没有,欢迎任何关于如何自己实施它的建议。

【问题讨论】:

    标签: inheritance methods groovy interface annotations


    【解决方案1】:

    您应该查看traits,它们是处理此类情况的 Groovy 方式。这有点像扩展一个类,但是您可以使用任意数量的特征来实现它。有方法重叠的规则,以及确定调用哪个 trait 方法的方法。您的注释也应该可以正常工作。

    trait Credentials {
        String username
    
        @Option(name = '-username')
        void setUsername(String aUsername){
            username = aUsername}
    
        @Option(name = '-password')
        abstract void setPassword(String username)
    
        String getUsername() {return username}
    
        abstract String getPassword()
    }
    
    class CredentialsImpl implements Credentials {
        String password
    
        @Option(name = '-password')
        void setPassword(String password){ this.password = password}
        String getPassword() { password }
    }
    

    它们也可以在运行时添加到对象中

    def 'does recognise option from interface via @Delegate'() {
        given:
            def parser = new CmdLineParser(new Object() as Credentials )
    
        when:
            parser.parseArgument('-username=John', '-password=qwerty123', '-url=http://auth.plop.com')
    
        then:
        with(options) {
            username == 'John'
            password == 'qwerty123'
            url == 'http://auth.plop.com'
        }
      }
    

    【讨论】:

    • 哦,我很确定我正在尝试使用特征,并且我得到了与接口相同的确切结果。不过我会再看一遍,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    • 2013-12-30
    • 2015-05-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多