Hello!
I am developing a Java application where Clojure is used as a library. The
application is required to load sources (including Clojure sources) from
arbitrary locations in filesystem, internet and maybe a dozen other places.
Hence I have developed corresponding classloaders for that, which properly
implement the required ClassLoader methods.
Loading Clojure sources is realized via this approach:
Compiler.LOADER.alterRoot(getMyClassLoader(), ...); // changing
the LOADER to my chain of classloaders
IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("example.namespace"));
where the contents of the "example.namespace" are:
(ns example.namespace
(:require [other.example.namespace :as other])))
I have figured that the loading happens with RT.load()
<https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L415>
which delegates to RT.loadResourceScript()
<https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L365>,
so
I just alter the Compiler.LOADER so that RT.baseLoader() returns my
classloaders. And in my classloaders I simply have to override the
getResourceAsStream
and all works!
The namespace example.namespace starts loading ok. It successfully loads
the whole clojure.core and then begins to process the first require - the
other.example.namespace. And this is where something *bad *happens.
It appears to be that the (require) inside the ns form in the
example.namespace uses not the RT.load() method, but Compiler.load()
<https://github.com/clojure-android/clojure/blob/android/src/jvm/clojure/lang/Compiler.java#L7202>where
on line 7210
<https://github.com/clojure-android/clojure/blob/android/src/jvm/clojure/lang/Compiler.java#L7210>the
Compiler.LOADER, which by that moment points to the correct classloader
created by me, gets replaced by RT.makeClassLoader()
<https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L2106>where
the current RT.baseLoader() which is effectively Compiler.LOADER gets
passed as the parent to the newly created DynamicClassLoader.
So I get Compiler.LOADER which I have set to the correct classloader,
replaced by the DynamicClassLoader whose parent is my classloader. The
problem is that DynamicClassLoader inherits from URLClassLoader that
inherits from ClassLoader which, although accepts a parent classloader on
its creation, does not delegate getResourceAsStream() in case of its
personal failure to its parent
<http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/ClassLoader.java#1175>!
That
results in that my classloader, although still present in the chain, never
gets called and the (require) in the ns form of example.namespace fails to
locate the required namespaces that **are** available at that data source.
The problem is that this behavior is hard-coded in Clojure and it looks
like it is impossible to change that. Clojure forces us to use a
classloader that inherits the getResourceAsStream() method from
java.lang.ClassLoader which does not allow delegation of this request to
parent classloader. This effectively prevents using Clojure as a library
together with a plugin system because it renders Clojure incapable of
working with sources that are fetched from elsewhere than the Java's
URLClassLoader is capable of retrieving data from. It is impossible to load
sources from a database, or some internet data source or an encrypted data
source, or even another location in the filesystem. Wow!
We've went with Clojure and now are in the desperate need to resolve this
peculiar phenomenon.. What could be a proposed solution for this situation?
Thank you.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.