On 07.07.25 02:10, Saravanan Palanichamy wrote:
Hello Groovy users

I am looking for help in setting up my class loaders with the Groovy compiler. This is my understanding so far

 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 compilers can be used internally and externally. Unless I misunderstand what you mean with "external tool".

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

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


However, the compiler sometimes will add class nodes as part of AST transformations (Class nodes created with ClassHelper.create) ... In that case, which class loader should be used for creating these class nodes? Or does it not matter (I think it matters because I may use a 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, because that is what the compiler requires.

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

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

T is the transform loader, that can be used extra to load transforms. T needs to use the same Groovy lib, the facade of the transform must be in 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 compilation as well uses for example an inner loader for D, allowing recompilation of classes to some extend.

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


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

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


there is actually one more variant of class loaders you can use. Have the Groovy library as parent and then a class loader that contains your classes you want to compile against as child. D would be then be a child of this. T can be a child of G, if you need not to load any of those 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 itself and for the classes you compile against and if you really want T to be separate.

bye Jochen

Reply via email to