英文:
LinkageError when using HotswapAgent/DCEVM with Clojure REPL
问题
我正在尝试在一个混合的Clojure/Java Leiningen项目中使用HotswapAgent/DCEVM,以避免在重新编译Java源代码后必须重新启动REPL(我已经了解其他方法,如JRebel和Virgil)。
简而言之,问题是,在重新加载我重新编译的Java类之后,我会得到一个LinkageError
,似乎类没有重新加载。
为了提供更多细节,我已经设置了~/.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"
... ;; 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 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)
,但实际上我得到了以下错误:
Execution error (LinkageError) at dcevm-complex-demo.ad/raise-to-power
(ad.clj:10). loader constraint violation: when resolving method 'AD
AD.raiseToPower()' the class loader clojure.lang.DynamicClassLoader
@7c53a0c2 of the current class, dcevm_complex_demo/ad$raise_to_power,
and the class loader 'app' for the method's defining class, AD, have
different Class objects for the type AD used in the signature
(dcevm_complex_demo.ad$raise_to_power is in unnamed module of loader
clojure.lang.DynamicClassLoader @7c53a0c2, parent loader
clojure.lang.DynamicClassLoader @1217a2dd; AD is in unnamed module of
loader 'app')
完整的REPL交互如下图所示:
我该如何使类AD
的重新加载工作?我怀疑我可能需要更改函数clojure.lang.RT.baseLoader()
(clojure/lang/RT.java),但我不太确定如何操作。
英文:
I am trying to use HotswapAgent/DCEVM in a mixed Clojure/Java Leiningen project in order to avoid having to restart the REPL after recompiling the Java source code (I am already aware of other approaches to this, such as JRebel and Virgil).
In short, the problem is that I get a LinkageError
after reloading a Java class that I recompiled, and it seems like the class does not get reloaded.
To provide more details, I have set up my ~/.lein/profiles.clj
so that in the :repl
profile, we use the current version of DCEVM JVM found here to run the REPL. This is the relevant portion of 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
To reproduce the problem, I have set up a minimal mixed Leiningen Clojure and Java project with a small Java class AD
with this code:
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 + ")";
}
}
and a small piece of Clojure code that imports this class:
(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))
Then I start a Clojure REPL in Emacs/CIDER, load the dcevm-complex-demo.ad
namespace and evaluate the expression (raise-to-power (variable 3.0))
which produces the result AD(value=81.0, deriv=108.0)
. I then modify the Java source code, for example, I change the line public static int EXPONENT = 4;
to public static int EXPONENT = 3;
and recompile using lein javac
in the terminal. A message in the REPL tells me the class AD
was reloaded. But then when I re-evaluate the expression (raise-to-power (variable 3.0))
I would expect the result AD(value=27.0, deriv=27.0)
, but instead I get this error:
> Execution error (LinkageError) at dcevm-complex-demo.ad/raise-to-power
> (ad.clj:10). loader constraint violation: when resolving method 'AD
> AD.raiseToPower()' the class loader clojure.lang.DynamicClassLoader
> @7c53a0c2 of the current class, dcevm_complex_demo/ad$raise_to_power,
> and the class loader 'app' for the method's defining class, AD, have
> different Class objects for the type AD used in the signature
> (dcevm_complex_demo.ad$raise_to_power is in unnamed module of loader
> clojure.lang.DynamicClassLoader @7c53a0c2, parent loader
> clojure.lang.DynamicClassLoader @1217a2dd; AD is in unnamed module of
> loader 'app')
This is what the full REPL interaction looks like:
How can I make the reloading of the class AD
work? I suspect that I might have to change the function clojure.lang.RT.baseLoader()
(clojure/lang/RT.java) but I am not quite sure how to go about that.
答案1
得分: 0
在dcevm8和dcevm11中都存在关于lambda重新定义的问题。这个问题已经在dcevm v11.0.7+1中得到了解决。根据您的日志,这可能会有所帮助。
链接:https://github.com/TravaOpenJDK/trava-jdk-11-dcevm/releases/tag/dcevm-11.0.7+1
英文:
There was a problem with lambda redefinition both in dcevm8 and dcevm11. This issue was resolved in dcevm v11.0.7+1. According your logs it could help.
https://github.com/TravaOpenJDK/trava-jdk-11-dcevm/releases/tag/dcevm-11.0.7+1
专注分享java语言的经验与见解,让所有开发者获益!
评论