Hi Saravanan, Do I assume right in that you are trying to use a Kotlin defined Annotation in Groovy? Isn't in Kotlin a @Repeatable required? At least I read that from https://kotlinlang.org/docs/annotations.html#repeatable-annotations Or in this case I would have expected @JvmRepeatable(MyGroupAnnotation::class) on MyAnnotation.
I would suggest, that you first try to make what you try to get done with normal Java or Groovy based annotations. After that we can then compare the Kotlin and the Java version on the bytecode level to actually see what (if anything) is different. For example when you say you load "someMethod from a jar or class path" then I would have before assumed you do this using Java or Groovy. But now this could be also Kotlin. If Kotlin is loading those classes it may do something to them I do not know. This is complete speculation on my side of course, but something I cannot exclude as option. That is why it is important to make such a scenario as bare-bone as possible. bye Jochen On 10.03.22 16:11, Saravanan Palanichamy wrote:
Thank you Jochen I further narrowed this down to this behaviour * I have an annotation MyAnnotation. This is marked as SOURCE retention and is used as a repeatable annoation * I have another annotation MyGroupAnnotation. This is marked as RUNTIME retention * I have an AST transformation that removes all MyAnnotation on the type it is defined on and collates them into MyGroupAnnotation @MustBeDocumented @Retention(AnnotationRetention.SOURCE) @Target(AnnotationTarget.FUNCTION) annotation class MyAnnotation(...) @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FUNCTION) annotation class MyGroupAnnotation( val all:Array<RemoteActivity> = [] ) This is how I use it @MyAnnotation(...) @MyAnnotation(...) List<MyStuff> someMethod(List<MyStuff> blah) And this is how it ends up after the AST @MyGroupAnnotation(all = [MyAnnotation(...), MyAnnotation(...)]) List<MyStuff> someMethod(List<MyStuff> blah) When I use someMethod, if it has already been loaded separately by the same class loader, the MethodNode representing someMethod contains 1 annotation (MyGroupAnnotation) with 1 member which is a list but that list has one NULL value in it This seems to be because it goes through Java8::annotationValueToExpression(...) through the array section and then back into annotationValueToExpression where it sees an instance of a proxy object instead of a Class definition. So it returns NULL Not sure if this rings any bells, I am lost though. This seems to work if I load someMethod from a jar or class path. This only fails if I use the same class loader that compiled someMethod regards Saravanan On Fri, Mar 4, 2022 at 5:44 PM Jochen Theodorou <blackd...@gmx.org <mailto:blackd...@gmx.org>> wrote: On 15.02.22 05:20, Saravanan Palanichamy wrote: > Hello Groovy users > > I am using Groovy 3.0.5 > > * I have a file A.groovy and B.groovy. B depends on A > * I have ast transformations that add annotations to methods in A > (specifically an annotation with a list expression that contains > other annotations) > * I compile A.groovy using the loadClass and then compile B.groovy > again with load class. When I inspect a method call to A(using the > method target field inside method call expression), I see only null > values for the annotations I added > * If I compiled B.groovy and have it automatically detect A.groovy, I > see the right values for my annotations (no nulls) > > Any idea why this is happening? If the annotations are directly in the file, then the one way this makes sense to me is that you load a different A. That would mean your class loader you use for B finds a different A, then the one you loaded (given you loaded the right A of course). Without further details about the setup this is a bit difficult. I suggest you do the following style of test: * loadClass for A, and keep a reference to A: x=loadClass("A") * have B return the class A (something like "return A.class") * loadClass for B and execute the code that returns A: y=loadClass("B").getA() * now the first A and the second A must be fulfilling referential identity: assert x===y If the assert fails it is clear that you are doing something wrong with your class loaders. If the assert does not fail I suggest to stop after loading A and checking that the annotations are on it. If they are not, you load the wrong A - wherever A is coming from. If they are there, but later not... well then you created some very very strange case that violates classloader constraints, because that means A has been modified after the class has been loaded, without loading a new A. Not sure you can do that even with instrumentation to that extend. bye Jochen