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 >>>>> >>>>>