You beat me to it! Thanks! I updated the description, please take a look.
On Tue, Nov 17, 2020 at 16:45 Paul King <pa...@asert.com.au> wrote: > I created this: > https://issues.apache.org/jira/browse/GROOVY-9817 > > On Tue, Nov 17, 2020 at 2:11 PM Remko Popma <remko.po...@gmail.com> wrote: > >> Eric and Paul, >> Thank you both for your responses! >> >> Paul, >> Thank you for your quick turnaround on supporting array annotations! >> >> I will create a Jira ticket when I get to my PC. >> >> Remko >> >> On Nov 17, 2020, at 12:24, Paul King <pa...@asert.com.au> wrote: >> >> >> The following runs fine after adding in array support: >> >> import java.lang.annotation.* >> import org.codehaus.groovy.runtime.InvokerHelper >> >> class ClosureTest { >> static class Demo { >> @Option(names = "-x", >> completionCandidates = {["A", "B", "C"]}, >> converter = [{ str -> >> java.security.MessageDigest.getInstance(str) }]) >> java.security.MessageDigest digest >> } >> >> static void main(String[] args) { >> def annotation = >> Demo.getDeclaredField("digest").getAnnotation(Option) >> Class comp = annotation.completionCandidates() >> assert comp != null >> assert Closure.isAssignableFrom(comp) >> assert ["A", "B", "C"] == InvokerHelper.invokeConstructorOf(comp, >> [null, null] as Object[])() >> >> Class[] conv = annotation.converter() >> assert conv != null >> assert conv.length == 1 >> assert Closure.isAssignableFrom(conv[0]) >> assert 'SHA-1' == InvokerHelper.invokeConstructorOf(conv[0], >> [null, null] as Object[])('SHA-1').algorithm >> } >> } >> >> interface ITypeConverter<K> { >> K convert(String value) throws Exception >> } >> >> class NoCompletionCandidates {} >> >> @Retention(RetentionPolicy.RUNTIME) >> @Target([ElementType.FIELD]) >> @interface Option { >> Class<? extends ITypeConverter<?>>[] converter() default [] >> Class<? extends Iterable<String>> completionCandidates() default >> NoCompletionCandidates >> String names() >> } >> >> Probably worth adding. Did you want to create a Jira? >> >> Cheers, Paul. >> >> >> On Tue, Nov 17, 2020 at 12:32 PM Paul King <pa...@asert.com.au> wrote: >> >>> The Closure to Class conversion doesn't currently support arrays. If you >>> change converter() to take just a single convert, your example works >>> for me. >>> >>> Supporting arrays might be an interesting enhancement. I'll take a look >>> at what would be involved. >>> >>> Cheers, Paul. >>> >>> >>> On Tue, Nov 17, 2020 at 11:02 AM Remko Popma <remko.po...@gmail.com> >>> wrote: >>> >>>> I’m probably overlooking something simple but I’m not seeing it yet. >>>> >>>> The below code demonstrates the issue when trying to pass a Groovy >>>> closure to the @Option(converter = ...)attribute: >>>> >>>> class ClosureTest { >>>> static class Demo { >>>> @picocli.CommandLine.Option(names = "-x", >>>> completionCandidates = {["A", "B", "C"]}, >>>> converter = [{ str -> >>>> java.security.MessageDigest.getInstance(str) }]) >>>> java.security.MessageDigest digest >>>> } >>>> >>>> static void main(String[] args) { >>>> def annotation = >>>> Demo.class.getDeclaredField("digest").getAnnotation(picocli.CommandLine.Option) >>>> Class ok = annotation.completionCandidates() >>>> assert ok != null >>>> assert Closure.class.isAssignableFrom(ok) >>>> assert ["A", "B", "C"] == ((Closure) ok.getConstructor(Object, >>>> Object).newInstance(null, null)).call() >>>> >>>> Class[] bad = annotation.converter() >>>> assert bad != null >>>> assert bad.length == 1 // this assert fails: >>>> //Exception in thread "main" Assertion failed: >>>> // >>>> //assert bad.length == 1 >>>> // | | | >>>> // [] 0 false >>>> // >>>> // at >>>> org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:434) >>>> // at >>>> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:670) >>>> // at closure.ClosureTest.main(ClosureTest.groovy:18) >>>> } >>>> } >>>> >>>> >>>> >>>> >>>> On Mon, Nov 16, 2020 at 21:16 Remko Popma <remko.po...@gmail.com> >>>> wrote: >>>> >>>>> PS >>>>> >>>>> The ITypeConverter interface definition is here: >>>>> https://picocli.info/apidocs/picocli/CommandLine.ITypeConverter.html >>>>> >>>>> >>>>> On Mon, Nov 16, 2020 at 21:08 Remko Popma <remko.po...@gmail.com> >>>>> wrote: >>>>> >>>>>> Hi all, >>>>>> >>>>>> I have a question about passing closures to annotations in Groovy. >>>>>> To illustrate, consider the @Option annotation in the picocli library. >>>>>> Relevant attributes are `completionCandidates` and `converter`, >>>>>> defined in Java as follows: >>>>>> >>>>>> @Retention(RetentionPolicy.RUNTIME) >>>>>> @Target({ElementType.FIELD, ElementType.METHOD, >>>>>> ElementType.PARAMETER}) >>>>>> public @interface Option { >>>>>> Class<? extends ITypeConverter<?>>[] converter() default {}; >>>>>> Class<? extends Iterable<String>> completionCandidates() default >>>>>> NoCompletionCandidates.class; >>>>>> ... >>>>>> } >>>>>> >>>>>> I am working on a change to picocli >>>>>> <https://github.com/remkop/picocli/issues/1258> that would allow >>>>>> users to specify closures for these and other attributes. >>>>>> User code could look like this: >>>>>> >>>>>> @Option(names = '-s', completionCandidates = {["A", "B", "C"]}) >>>>>> @Field String s >>>>>> >>>>>> @Option(names = '-a', converter = [{ str -> >>>>>> MessageDigest.getInstance(str) }] ) >>>>>> @Field MessageDigest algorithm >>>>>> >>>>>> I think this would be a nice addition and would make picocli more >>>>>> "groovy". >>>>>> >>>>>> I have a prototype implementation, but it appears that only the first >>>>>> example ( completionCandidates = {["A", "B", "C"]} ) works as >>>>>> expected. >>>>>> When stepping through my prototype test in a debugger, it looks like >>>>>> the second example (the converter attribute) receives a zero-length >>>>>> array of classes when invoked from Groovy. I tried with Groovy 2.4.10 and >>>>>> 3.0.6. >>>>>> >>>>>> Is this a known limitation of Groovy? >>>>>> Is there a way to work around this? >>>>>> >>>>>> I can provide an example project to reproduce this if that is helpful. >>>>>> >>>>>> Kind regards, >>>>>> Remko >>>>>> >>>>>>