Я пытаюсь использовать HotswapAgent / DCEVM в смешанном проекте Clojure / Java Leiningen, чтобы избежать необходимости перезапуска REPL после перекомпиляции исходного кода Java (мне уже известно о другие подходы к этому, такие как 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))
Затем я запускаю REPL Clojure в Emacs / CIDER, загружаю пространство имен 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)
, но вместо этого получаю эту ошибку:
Ошибка выполнения (LinkageError) в dcevm-complex-demo.ad / повышение власти (ad.clj: 10). Нарушение ограничения загрузчика: при разрешении метода AD AD.raiseToPower () загрузчик класса clojure.lang.DynamicClassLoader @ 7c53a0c2 текущего класса, dcevm_complex_demo / ad $ поднимает_to_power и загрузчик классов app для класса, определяющего метод, AD , иметь разные объекты Class для типа AD, используемого в подписи (dcevm_complex_demo.ad $ lift_to_power находится в неназванном модуле загрузчика clojure.lang.DynamicClassLoader @ 7c53a0c2, родительский загрузчик clojure.lang.DynamicClassLoader @ 1217a2dd; AD находится в неназванном модуле loader 'app')
Вот как выглядит полное взаимодействие REPL:
Как я могу заставить перегрузить класс AD
работать? Я подозреваю, что мне, возможно, придется изменить функцию clojure.lang.RT.baseLoader()
( clojure / lang / RT. java), но я не совсем уверен, как go узнать об этом.