Over a million developers have joined DZone.

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

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

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!

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

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

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

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

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

{{ parent.tldr }}

{{ parent.urlSource.name }}