2015-06-15 1 views
2

Мой пример выполнен с помощью Koshuke args4j's@Option аннотация, но то же самое применимо к любой другой аннотации метода. Чтобы уточнить, эта аннотация может использоваться с любым полем или сеттером.Есть ли способ наследовать аннотацию метода интерфейса в Groovy? (возможный сбой в @Delegate)

Он работает следующим образом:

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 имеет их. И нет наследования аннотаций метода ... о, подождите, на самом деле в этом суть. Кажется, это сбой. Почему @Delegate способен воспринимать эти аннотации, указанные на уровне интерфейса, если они не унаследованы CredentialsImpl?

С другой стороны, я хотел бы иметь точно такое поведение как функции, так что я не должен был бы использовать делегирование здесь, вместо того, чтобы идти, как:

@InheritInterfaceMethodAnnotations 
class SomeOptionsViaInterface implements Credentials { 
    String username 
    String password 

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

Очевидно соответствующего теста для приведенного выше примера провалился бы так же, как для второго примера. Таким образом, вопрос: есть ли что-то вроде мнимой аннотации, которую я составил - @InheritInterfaceMethodAnnotations? Возможна установка с учетом @Delegate сбой. Как представляется, это полезная функция, возможно, кто-то уже это сделал. Если нет, любой совет, как реализовать его сам по себе, приветствуется.

ответ

0

Вы должны посмотреть на traits, они являются способом Groovy для обработки подобных ситуаций. Это похоже на расширение класса, но вы можете сделать это с таким количеством признаков, сколько хотите. Существуют правила перекрытия методов и способы определения способа вызова метода. Ваши аннотации также должны работать.

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' 
    } 
    } 
+0

О, я уверен, что я экспериментировал с чертами, и я был точно такой же результат, как и с интерфейсами. Я еще раз посмотрю, спасибо. – topr

Смежные вопросы