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