Is there an instance in the core language/runtime where a closure literal is 
used as part of an annotation but not for an AST transformation?  I'm not sure 
what the compiler does when it encounters a closure expression as the value for 
an annotation attribute (of type Class).  But the AST transforms that do this 
-- ASTTest and AutoImplement come to mind -- take the closure code and use it 
to generate methods.  I think GContracts is this way as well.

After reading your example more closely, I see that a single-valued annotation 
attribute works as expected but the multi-value case fails.

From: Remko Popma <remko.po...@gmail.com>
Sent: Monday, November 16, 2020 7:02 PM
To: Groovy_Developers <dev@groovy.apache.org>
Subject: Re: Closures in annotations

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<mailto:remko.po...@gmail.com>> wrote:
PS

The ITypeConverter interface definition is here:
https://picocli.info/apidocs/picocli/CommandLine.ITypeConverter.html<https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpicocli.info%2Fapidocs%2Fpicocli%2FCommandLine.ITypeConverter.html&data=04%7C01%7Ceric.milles%40thomsonreuters.com%7C1c5e266b8280484ce44c08d88a94782d%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637411717560284723%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=FNAGjAoww3EIKmOnW1kRvE3ZDTQF7k5Ar0Hbo0oHi2k%3D&reserved=0>


On Mon, Nov 16, 2020 at 21:08 Remko Popma 
<remko.po...@gmail.com<mailto: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://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fremkop%2Fpicocli%2Fissues%2F1258&data=04%7C01%7Ceric.milles%40thomsonreuters.com%7C1c5e266b8280484ce44c08d88a94782d%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637411717560284723%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=AzDZ2%2F5vCf88nV%2BgT3r%2BKBTYW%2BGrrnHUuaduX6ibIsM%3D&reserved=0>
 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