简体   繁体   中英

LinkageError when using HotswapAgent/DCEVM with Clojure REPL

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:

REPL 交互

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM