Re: Class loaders to use

Jochen Theodorou <[email protected]> Mon, 7 Jul 2025 12:40:03 +0200
Newsgroups gmane.comp.lang.groovy.user
Message-ID <[email protected]>
On 07.07.25 02:10, Saravanan Palanichamy wrote:
> Hello Groovy users
>=20
> I am looking for help in setting up my class loaders with the Groovy=20
> compiler. This is my understanding so far
>=20
>  1. The compiler is an external tool to compile (Groovy is a java based
>     compiler) and therefore it must have its own class paths and a class
>     loader to load libraries it needs (the COMPILER class loader). This
>     includes the transform loaders needed for static compilation etc
>  2. The compiled code has its own set of class paths and there must have
>     a separate class loader (the CLASSPATH class loader)
>  3. The two should be completely separate (I think)

the Groovy compiler is not based on the java compiler. And both=20
compilers can be used internally and externally. Unless I misunderstand=20
what you mean with "external tool".

It does need a class loader, because that is used to find classes during=
=20
compilation. If you for example compile "class X extends Foo", then Foo=20
needs to be found. For example the compiler has to check if the class is=
=20
final, if it has abstract methods and many more things.

The transform loader is needed for compilation regardless of static or=20
not. those transforms consists of a front class in form of an annotation=
=20
and a backing class, with the actual implementation. The front class=20
must be visible in the normal class loader to find classes, the=20
implementing class must be visible by the transform loader. Both loaders=
=20
must have a parent knowing the same groovy library, or be that loader=20
itself. The compiler will then use the transform loader to load and=20
execute the transform.


> However, the compiler sometimes will add class nodes as part of AST=20
> transformations (Class nodes created with ClassHelper.create) ... In=20
> that case, which class loader should be used for creating these class=20
> nodes? Or does it not matter (I think it matters because I may use a=20
> different version of jar in the compiler vs the compiled code)

Let me try some ascii art

>   G
>  / \
> D   T

So D and T have as parent G

These loaders could be all one loader long as it is a GroovyClassLoader,=
=20
because that is what the compiler requires.

D is the defining class loader for classes produced by the compiler. D=20
is really only used if there is no target directory given I think. the=20
FileSystemCompiler for example compiles to the file system, not to in=20
memory classloaders. GroovyShell on the other hand typically does not=20
compile to the file system.

G is the class loader used by the compiler to find classes. The compiler=
=20
thus sees all classes visible to G. In the FileSystemCompiler we tend to=
=20
make one classloader for G load all those classes from the classpath,=20
but of course G can have parents as well. G is the loader containing the=
=20
Groovy library itself, including the compiler and all helper classes of=20
the normal compiler.

T is the transform loader, that can be used extra to load transforms. T=20
needs to use the same Groovy lib, the facade of the transform must be in=
=20
C, otherwise the compiler cannot find it and the implementing code in T.

A usual scenario is to do

>  GT
>  |
>  D

meaning G and T are the same loader. GroovyClassLoader, if used for=20
compilation as well uses for example an inner loader for D, allowing=20
recompilation of classes to some extend.

Anyway... as I said you can merge the loader with the parent in my=20
structure and still get a valid setup for class loading if you want to=20
do it like that.


> If I have to use the CLASSPATH class loader for creating class nodes,=20
> are there standard patterns to help do this (given that=20
> ClassHelper.create is a static method)?

You mean classes nodes for preexisting classes, which we do not compile.=
=20
You mean ClassHelper.make, which does not safe the created ClassNode. It=
=20
is safe for compiling with it multiple times, just do not the=20
"withCaching" methods.


there is actually one more variant of class loaders you can use. Have=20
the Groovy library as parent and then a class loader that contains your=20
classes you want to compile against as child. D would be then be a child=
=20
of this. T can be a child of G, if you need not to load any of those=20
classes you compile against in T, or if you do a child of that loader.

But maybe you describe a bit the structure you want to have Groovy=20
itself and for the classes you compile against and if you really want T=20
to be separate.

bye Jochen