2012-06-07 11 views
5

Sono stato reimpostato in un servizio in esecuzione e ho una var che punta a un classloader con cui è stato caricato un plugin (con my.package installato).Class/forName in Clojure che non rispetta ContextClassLoader?

Il DynamicClassLoader utilizzato da REPL non include il plug-in con cui desidero interagire; Vorrei poter lavorare con le classi caricate dal plugin nonostante questa limitazione.

le seguenti opere:

=> (.loadClass plugin-classloader "my.package.MyClass") 
my.package.MyClass 

... mentre la seguente non (ignorando esplicitamente il programma di caricamento classe contesto del thread):

=> (do 
    (.setContextClassLoader (Thread/currentThread) plugin-classloader) 
    (Class/forName "my.package.MyClass")) 
ClassNotFoundException my.package.MyClass java.net.URLClassLoader$1.run (URLClassLoader.java:202) 

... e nemmeno questo (in modo esplicito l'override il classloader contesto di thread e il riferimento clojure.lang.Compiler/LOADER):

=> (let [dcl (clojure.lang.DynamicClassLoader. plugin-classloader)] 
    (.setContextClassLoader (Thread/currentThread) dcl) 
    (with-bindings* {clojure.lang.Compiler/LOADER dcl} 
     (eval '(pr-str (Class/forName "my.package.MyClass"))))) 
ClassNotFoundException my.package.MyClass  java.net.URLClassLoader$1.run (URLClassLoader.java:202) 

... e nemmeno questo:

=> my.package.MyClass 
CompilerException java.lang.ClassNotFoundException: my.package.MyClass, compiling:(NO_SOURCE_PATH:0) 

Non dovrebbe Class.forName() utilizzare il contesto di caricamento classe thread quando set? Sto provando a fare alcune chiamate nel codice di terze parti facendo magia introspettiva; gli strumenti in questione stanno fallendo con ClassNotFoundExceptions anche quando il classloader del contesto di thread deve essere impostato.


Nel caso in cui sto impostando esplicitamente il classloader contesto, l'analisi dello stack dimostra che di Clojure DynamicClassLoader (piuttosto che il BundleClassLoader nel plugin-classloader var) è in uso:

=> (e) 
java.lang.ClassNotFoundException: my.package.MyClass 
at java.net.URLClassLoader$1.run (URLClassLoader.java:202) 
    java.security.AccessController.doPrivileged (AccessController.java:-2) 
    java.net.URLClassLoader.findClass (URLClassLoader.java:190) 
    clojure.lang.DynamicClassLoader.findClass (DynamicClassLoader.java:61) 
    java.lang.ClassLoader.loadClass (ClassLoader.java:306) 
    java.lang.ClassLoader.loadClass (ClassLoader.java:247) 
    java.lang.Class.forName0 (Class.java:-2) 
    java.lang.Class.forName (Class.java:169) 
+0

Sembra come 'eval' sta giocando qualche trucco c'è ... si può provare stessa cosa nel codice del clojure compilato? – Ankur

+0

@Ankur - Intendi compilato AOT? La mia comprensione è che l'implementazione di Clojure è tale che è * tutto * codice compilato, anche inserito al REPL. –

+0

@Ankur Come si è visto, hai avuto ragione: è un codice compilato, ma l'istanza di 'DynamicClassLoader' associata a' clojure.lang.Compiler/LOADER' quando 'clojure.lang.Compiler/eval' è chiamato questione . –

risposta

5

clojure.lang.Compiler/eval, come richiesto dal REPL, utilizza clojure.lang.Compiler/LOADER, non il classloader locale del thread. Un programma di caricamento classe appropriata deve legato a questo var prima eval è chiamato - in modo da aggiungere uno strato di confezionamento opere risolvere questo problema:

=> (let [dcl (clojure.lang.DynamicClassLoader. plugin-classloader)] 
    (with-bindings {clojure.lang.Compiler/LOADER dcl} 
     (eval '(Class/forName "my.package.MyClass")))) 
my.package.MyClass 
Problemi correlati