Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Class Loading Fun with Groovy

DZone's Guide to

Class Loading Fun with Groovy

Sometimes you need special measures. Not to make Groovy work, but to make your applications or frameworks a little bit more powerful or versatile.

· Java Zone
Free Resource

Bitbucket is for the code that takes us to Mars, decodes the human genome, or drives your next car. What will your code do? Get started with Bitbucket today, it's free.

Sometimes you need special measures. Not to make Groovy work, but to make your applications or frameworks a little bit more powerful or versatile.

Here are two class loading techniques that I've used in combination with Groovy to make life more fun and interesting.

One: getting rid of Groovy

Sometimes you have to get hold of a ClassLoader that doesn't include the Groovy classes. Sometimes you need to have a ClassLoader that only contains the classes shipped with the JVM.

Every Java application has a ClassLoader that only contains JVM classes and you can get hold of it, if you know how.

The java.lang.ClassLoader class has a static getSystemClassLoader() method that returns a ClassLoader that contains all classes on the CLASSPATH when the JVM started:

ClassLoader.systemClassLoader.loadClass "some.class.on.the.ClassPath"

This ClassLoader has one or more parent ClassLoaders. The ClassLoader on top of this hierarchy is the one that only contains JVM classes. When you find a ClassLoader without parent you know you've found it:

def classLoader = ClassLoader.systemClassLoader
while (classLoader.parent) {
       classLoader = classLoader.parent
}

This little routine gets you the top ClassLoader. You can now use this one to create a new ClassLoader hierarchy. It only takes creating a new URLClassLoader and provide the locations of the JAR files you want to include:

def classLoader = ClassLoader.systemClassLoader
while (classLoader.parent) {
classLoader = classLoader.parent
}
def newClassLoader = new URLClassLoader([new File("location/to.jar").toString().toURL()] as URL[], classLoader)

You now have a new ClassLoader. Warning: it does not include Groovy if you don't add the Groovy JAR specifically, and any classes that have already been loaded will be loaded again, increasing the memory foot-print of your application. Also, don't create too many new ClassLoaders in one application since they tend to cause memory leaks. Creating one or a few should be fine. Classes loaded with the new ClassLoader will not be compatible with classes loaded by the current system ClassLoader, except for the JVM classes.

You can improve this code by using the org.apache.tools.ant.launch.Locator class (that ships with Ant). Its fileToURL() method does a slightly better job at converting java.io.File objects to java.net.URL methods.

Two: getting hold of GroovyClassLoader in Java code

Sometimes you have to get hold of a groovy.lang.GroovyClassLoader object in Java code. This may for example happen when Java code is called from Groovy code. GroovyClassLoaders tend the be at the bottom of ClassLoader hierarchies, and sometimes you want to load classes in GroovyClassLoader and not anywhere else in the ClassLoader hierarchy.

Your Java code however was most likely not loaded by the GroovyClassLoader, so how to get hold of it? You could pass is explicitly from your Groovy code but that's not practical. Instead, use the sun.reflect.Reflection class? Never heard of it? Then it's time to meet the getCallerClass() method.

When Groovy code calls Java code then somewhere up in the stack there is a Groovy class that's been loaded by a GroovyClassLoader. Here's how to get hold of it from Java code:

import sun.reflect.Reflection;
import groovy.lang.GroovyClassLoader;
public class MyClass {
public void myMethod() throws Exception {
int frame = 1;
// number of levels above you in the stack
Class c = Reflection.getCallerClass(frame); 
while (c != null && !(c.getClassLoader() instanceof GroovyClassLoader)) {
frame++;
c = Reflection.getCallerClass(frame);
}
if (c != null) {
GroovyClassLoader gcl = (GroovyClassLoader) c.getClassLoader();
// do Groovy stuff here
Class newClass = gcl.parseClass("class MyNewClass{}");
}       
}
}

These tricks show just how much Groovy is integrated with the JVM, and how Groovy generates proper Java byte-code.

Happy Groovy coding!

Bitbucket is the Git solution for professional teams who code with a purpose, not just as a hobby. Get started today, it's free.

Topics:
java ,groovy ,class ,loading ,classloader ,classpath

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}