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> 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
>
>

Reply via email to