Monday, March 05, 2012

Grails Class.forName (loading classes dynamically)

This is a quickie for now.. I will have to come back and expand this entry when I understand more of why it happens.

simple problem. Wanted to load classes dynamically based on a domain instance name.

Simple (in theory)

String name="Domain"
String className = "com.package.test."+name+"Service"
Object o =Class.forName(className).newInstance()

But it fails with a ClassNotFoundException. (and of course the class does exist).

After a lot of tested I came to the following answer
Object o = Thread.currentThread().contextClassLoader.loadClass(className).newInstance()
or
Object o = SomeOtherService.getClassLoader().loadClass(className).newInstance()

Why I don't know. One tends to work in unit tests and not in application code, and the opposite for the other, so often I include both

Here's some links that may help explain.
http://groovy.dzone.com/news/class-loading-fun-groovy

Based on this I wrote a simple test to check the different class loaders

def testB(){
    parseCL(this.getClass().getClassLoader()) //This ClassLoader does NOT work
        
    parseCL(AnotherService.getClassLoader()) // This class Loader does work
}
    
def parseCL(ClassLoader cl){
    println "********************"
    println cl
    println "********************"
    println "Parent ="+cl.getParent()
    cl = cl.getParent()
    def indent = "--"
    while(cl){
        println indent+cl
        cl = cl.getParent()
        println indent+"Parent ="+cl
        indent = indent +"--"
    }
}


Note the top level classloader is different

********************
java.net.URLClassLoader@247510e7 // DOES NOT LOAD CLASS DYNAMICALLY
********************
Parent =java.net.URLClassLoader@77479ef9
--java.net.URLClassLoader@77479ef9
--Parent =org.codehaus.groovy.grails.cli.support.GrailsRootLoader@15ded0fd
----org.codehaus.groovy.grails.cli.support.GrailsRootLoader@15ded0fd
----Parent =sun.misc.Launcher$AppClassLoader@35a16869
------sun.misc.Launcher$AppClassLoader@35a16869
------Parent =sun.misc.Launcher$ExtClassLoader@77cde100
--------sun.misc.Launcher$ExtClassLoader@77cde100
--------Parent =null
********************
java.net.URLClassLoader@77479ef9 // LOADS CLASS DYNAMICALLY
********************
Parent =org.codehaus.groovy.grails.cli.support.GrailsRootLoader@15ded0fd
--org.codehaus.groovy.grails.cli.support.GrailsRootLoader@15ded0fd
--Parent =sun.misc.Launcher$AppClassLoader@35a16869
----sun.misc.Launcher$AppClassLoader@35a16869
----Parent =sun.misc.Launcher$ExtClassLoader@77cde100
------sun.misc.Launcher$ExtClassLoader@77cde100
--------Parent =null

1 comment:

Anonymous said...

Thanks a lot!