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