2012-06-07 18 views
5

私は実行中のサービスにREPLされ、プラグインがロードされたクラスローダーを指し示すvarを持っています(my.packageがインストールされています)。ClojureのClass/forNameはContextClassLoaderを尊重していませんか?

REPLで使用されるDynamicClassLoaderには、相互作用したいプラグインは含まれていません。この制限にもかかわらず、プラグインからロードされたクラスで作業できるようにしたい。

次作品:

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

...以下は(明示的にスレッドコンテキストクラスローダをオーバーライド)しないのに対し:

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

...そしてどちらも、これは(明示的にオーバーライドしスレッドコンテキストクラスローダークローラーのコンパイラ/ロードのリファレンス):

=> (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) 

...とどちらもこれを行います:設定したときに

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

Class.forName()はスレッドコンテキストクラスローダを使用するべきではないでしょうか。私はイントロスペクション・マジックを行っている第三者コードにいくつかの呼び出しをしようとしています。スレッドコンテキストクラスローダーを設定する必要がある場合でも、問題のツールはClassNotFoundExceptionsで失敗します。

=> (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

eval'はそこにいくつかのトリックを再生している 'のように思える...あなたが同じことを試すことができますコンパイルされたクロージャーコードで? – Ankur

+0

@Ankur - あなたはAOTコンパイルを意味しますか?私の理解は、Clojureの実装はREPLで入力された*すべての*コンパイルされたコードであるということです。 –

+0

@Ankur 'clojure.lang.Compiler/eval'が問題と呼ばれるとき、' DynamicClassLoader'インスタンスは 'clojure.lang.Compiler/LOADER'にバインドされていました。 。 –

答えて

5

:私は明示的にコンテキストクラスローダを設定してる場合


は、スタックトレースは、ClojureののDynamicClassLoaderの(というよりも、プラグイン・クラスローダvarにBundleClassLoader)が使用中であることを示しています clojure.lang.Compiler/evalは、REPLによって呼び出されるため、スレッドローカルクラスローダではなく clojure.lang.Compiler/LOADERを使用します。 evalが呼び出される前に、適切なクラスローダは、このVARに結合する必要がある - そう、この問題の周りの作品を包むの層を追加:

=> (let [dcl (clojure.lang.DynamicClassLoader. plugin-classloader)] 
    (with-bindings {clojure.lang.Compiler/LOADER dcl} 
     (eval '(Class/forName "my.package.MyClass")))) 
my.package.MyClass 
関連する問題