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

Reply via email to