Oh, I see. Thanks for the clarification!
And thanks for the quick resolution! :-)

On Thu, Nov 19, 2020 at 12:17 Paul King <pa...@asert.com.au> wrote:

> I was just giving approx 72 hrs for feedback. Out of courtesy/caution more
> than a hard requirement for a change like this. I'll merge now.
>
> cheers, Paul.
>
> On Thu, Nov 19, 2020 at 9:09 AM Remko Popma <remko.po...@gmail.com> wrote:
>
>> Paul, just curious: is there anything preventing
>> https://github.com/apache/groovy/pull/1420 from being merged?
>>
>> On Tue, Nov 17, 2020 at 6:25 PM Paul King <pa...@asert.com.au> wrote:
>>
>>> Looks good, thanks!
>>>
>>> On Tue, Nov 17, 2020 at 6:11 PM Remko Popma <remko.po...@gmail.com>
>>> wrote:
>>>
>>>> You beat me to it! Thanks!
>>>> I updated the description, please take a look.
>>>>
>>>>
>>>> On Tue, Nov 17, 2020 at 16:45 Paul King <pa...@asert.com.au> wrote:
>>>>
>>>>> 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
>>>>>>>>>>
>>>>>>>>>>

Reply via email to