Re: Compiling several groovy files together

Jochen Theodorou <[email protected]>
Newsgroups gmane.comp.lang.groovy.user
Message-ID <[email protected]>
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 <[email protected]
> <mailto:[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
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.