Hey all,

Once again I'm lending my hand at trying to get some clojure code working under 
OSGi, and once again hitting issues with the good ole class loader. I have a 
simple OSGi bundle project which embeds clojure.jar, and contains a single 
source file:

    (ns com.theoryinpractise.activator.osgi.components
        (:import (org.osgi.framework BundleActivator)))

    (deftype MyActivator []
      BundleActivator
      (start [this context]
        (println "Hello from service"))
      (stop [this context]
          (println "stopping")))

In my OSGi metadata I have 
`com.theoryinpractise.activator.osgi.components.MyActivator` listed as the 
`Bundle-Activator` for the bundle, and when I load it I get the following 
exception:

    Caused by: java.lang.ExceptionInInitializerError
        at 
com.theoryinpractise.activator.osgi.components.MyActivator.<clinit>(components.clj:4)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at 
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at 
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        at java.lang.Class.newInstance(Class.java:374)
        at 
org.apache.felix.framework.Felix.createBundleActivator(Felix.java:4336)
        at org.apache.felix.framework.Felix.activateBundle(Felix.java:2141)
        ... 32 more
    Caused by: java.io.FileNotFoundException: Could not locate 
clojure/core__init.class or clojure/core.clj on classpath:
        at clojure.lang.RT.load(RT.java:443)
        at clojure.lang.RT.load(RT.java:411)
        at clojure.lang.RT.doInit(RT.java:447)
        at clojure.lang.RT.<clinit>(RT.java:329)
        ... 40 more
    java.lang.ExceptionInInitializerError

When I look at the decompiled class ( using JD-GUI ) I see there's a static 
initialiser pulling in the `println` function:

    public final class MyActivator implements BundleActivator, IType {
      public static final Var const__0 = (Var)RT.var("clojure.core", "println");
      …

Tracing this down into `RT.baseLoader()`:

    static public ClassLoader baseLoader(){
        if(Compiler.LOADER.isBound())
                return (ClassLoader) Compiler.LOADER.deref();
        else if(booleanCast(USE_CONTEXT_CLASSLOADER.deref()))
                return Thread.currentThread().getContextClassLoader();
        return Compiler.class.getClassLoader();
    }

I find that `Compiler.LOADER.isBound()` is false, and 
`booleanCast(USE_CONTEXT_CLASSLOADER.deref())` is true, which leads to using 
the class loader for the OSGi runtime and *not* the class loader that happens 
to actually know anything about Clojure, which would be the OSGi Bundle 
classloader for my package.

Does anyone know of a way around this? Or will I need to give up on trying to 
use pure-clojure here and use Java for my activator, and call 
`Compiler.LOADER.set(myclassloader)` and then do some `RT.*` love?

Cheers,
Mark
 

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to