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