我正在尝试在混合 Clojure/Java Leiningen 项目中使用HotswapAgent/DCEVM,以避免在重新编译 Java 源代码后必须重新启动 REPL(我已经知道其他方法,例如 JRebel 和 Virgil)。
简而言之,问题是我LinkageError
在重新加载我重新编译的 Java 类后得到了一个,并且似乎该类没有被重新加载。
为了提供更多详细信息,我~/.lein/profiles.clj
在配置文件中进行了设置,以便我们使用此处:repl
找到的当前版本的 DCEVM JVM来运行 REPL。这是的相关部分:profiles.clj
{:repl
{:plugins [[cider/cider-nrepl "0.22.4"]]
:dependencies [[org.clojure/tools.nrepl "0.2.13"]]
:java-cmd "/home/jonas/local/dcevm-11.0.6+1/bin/java"
... ;; Rest of profiles.clj
为了重现该问题,我使用以下代码设置了一个最小的 Leiningen Clojure 和 Java 混合项目,其中包含一个小型 Java 类AD
:
public class AD {
public double _value;
public double _deriv;
public static int EXPONENT = 4;
public AD(double value, double deriv) {
_value = value;
_deriv = deriv;
}
public AD mul(AD x) {
return new AD(_value*x._value, _value*x._deriv + _deriv*x._value);
}
public AD raiseToPower() {
AD result = new AD(1.0, 0.0);
for (int i = 0; i < EXPONENT; i++) {
result = result.mul(this);
}
return result;
}
public String toString() {
return "AD(value=" + _value + ", deriv=" + _deriv + ")";
}
}
以及一小段导入此类的 Clojure 代码:
(ns dcevm-complex-demo.ad
(:import AD))
(defn variable [x]
(AD. (double x) 1.0))
(defn raise-to-power
"Evaluates f(x) = x^n and f'(x), n being the AD/EXPONENT static variable"
[^AD ad-x]
(.raiseToPower ad-x))
然后我在 Emacs/CIDER 中启动 Clojure REPL,加载dcevm-complex-demo.ad
命名空间并评估(raise-to-power (variable 3.0))
产生结果的表达式AD(value=81.0, deriv=108.0)
。然后我修改Java源代码,例如,我将行更改public static int EXPONENT = 4;
为并在终端中public static int EXPONENT = 3;
重新编译使用。lein javac
REPL 中的一条消息告诉我该类AD
已重新加载。但是当我重新评估表达式时,(raise-to-power (variable 3.0))
我会期望得到结果AD(value=27.0, deriv=27.0)
,但我得到了这个错误:
dcevm-complex-demo.ad/raise-to-power (ad.clj:10) 处的执行错误 (LinkageError)。加载器约束违规:解析方法“AD AD.raiseToPower()”时,当前类 dcevm_complex_demo/ad$raise_to_power 的类加载器 clojure.lang.DynamicClassLoader @7c53a0c2 和方法定义类 AD 的类加载器“app” , 对于签名中使用的 AD 类型具有不同的 Class 对象(dcevm_complex_demo.ad$raise_to_power 在加载器 clojure.lang.DynamicClassLoader @7c53a0c2 的未命名模块中,父加载器 clojure.lang.DynamicClassLoader @1217a2dd;AD 在加载器的未命名模块中'应用程序')
这是完整的 REPL 交互的样子:
我怎样才能使类的重新加载AD
工作?我怀疑我可能必须更改函数clojure.lang.RT.baseLoader()
(clojure/lang/RT.java),但我不太确定如何去做。