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 <[email protected]> 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 <[email protected]> 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
>>
>>