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