[jetty-user] Classloader conflicts ?

Paul Bennett <[email protected]> Tue, 17 May 2011 09:52:08 -0400
Newsgroups gmane.comp.java.jetty.support
Message-ID <[email protected]>
I'm trying to embed Jetty in a Groovy app, but seemingly getting messed up by class loader conflicts. Given this:

class TestServlet extends HttpServlet {

    public void init()  {
        try {
            super.init();
        } catch (ServletException e) {
            e.printStackTrace();
        }
        ObjectStore store = ObjectStore.getInstance();
        println "Servlet gets store ID=${store}, class=${System.identityHashCode(store.class)}, loader=${store.class.classLoader}"
    }
}

class EmbeddedWebServer {

    Server server

    void start() {
        if(!server) {
            try {
                server = new Server(5001);

                ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
                context.setContextPath("/");
                context.setClassLoader(Thread.currentThread().getContextClassLoader());
                server.setHandler(context);

                println ("Thread class loader=${Thread.currentThread().getContextClassLoader()}");

                Servlet servlet = new TestServlet()

                println "ApplicationServlet gets ID=${servlet}, class=${System.identityHashCode(servlet.class)}, loader=${servlet.class.classLoader}"
                println "Servlet class gets loader=${Servlet.getClassLoader()}"
                println "ServletHolder class gets loader=${ServletHolder.getClassLoader()}"

                ServletHolder servletHolder = new ServletHolder(servlet)

                context.addServlet(servletHolder,"/*");
                server.start();
            } catch (Exception e) {
                server = null
                e.printStackTrace()
                return
            }
        }
    }

    void stop() {
        server.stop()
    }
}

When I run:

def store = ObjectStore.getInstance()
println "Startup gets store ID=${store}, class=${System.identityHashCode(store.class)}, loader=${store.class.classLoader}"
def ews = new EmbeddedWebServer().start()


I get the following:

Startup gets store ID=com.metaficient.core.store.ObjectStore@4e9e75f6, class=1237624300, loader=org.codehaus.groovy.tools.RootLoader@303bc257
Thread class loader=groovy.lang.GroovyClassLoader@29abc69
ApplicationServlet gets ID=com.metaficient.fast.scripts.TestServlet@221a5770, class=618337492, loader=org.codehaus.groovy.tools.RootLoader@303bc257
Servlet class gets loader=org.codehaus.groovy.tools.RootLoader@303bc257
ServletHolder class gets loader=sun.misc.Launcher$AppClassLoader@40affc70
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: org.eclipse.jetty.servlet.ServletHolder(com.metaficient.fast.scripts.TestServlet)
	at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1481)
	at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1397)
	at org.codehaus.groovy.runtime.callsite.MetaClassConstructorSite.callConstructor(MetaClassConstructorSite.java:46)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:52)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:198)
	at com.metaficient.fast.EmbeddedWebServer.start(EmbeddedWebServer.groovy:69)
	at com.metaficient.fast.EmbeddedWebServer$start.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at com.metaficient.fast.scripts.EmbeddedWebServerTest.run(EmbeddedWebServerTest.groovy:33)
	at groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:266)
	at groovy.lang.GroovyShell.run(GroovyShell.java:229)
	at groovy.lang.GroovyShell.run(GroovyShell.java:159)
	at groovy.ui.GroovyMain.processOnce(GroovyMain.java:496)
	at groovy.ui.GroovyMain.run(GroovyMain.java:311)
	at groovy.ui.GroovyMain.process(GroovyMain.java:297)
	at groovy.ui.GroovyMain.processArgs(GroovyMain.java:112)
	at groovy.ui.GroovyMain.main(GroovyMain.java:93)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
	at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)


My assumption is that the differing class loaders for ServletHolder and Servlet prevent the selection of the correct constructor on the highlighted line. What I don't understand is why ServletHolder is getting loaded with the App class loader. My understanding is that the loading class class loader would be used (which is RootLoader). I also don't understand how ServletHolder or the Jetty jars could change the class loader before being loaded

Any help much appreciated!