无法使用 ns 中另一个名称空间的 class :gen-class
Cannot use class from another namespace in ns :gen-class
我在 sre.plan.dsl.constraint
命名空间中有一个名为 ConstraintLookup
的 defrecord
。
我想在 sre.plan.compiler
命名空间的 gen-class
方法中使用其生成的 class:
(ns sre.plan.compiler
(:require
[sre.plan.dsl.constraint :as constraint])
(:import (sre.plan.dsl.constraint ConstraintLookup))
(:gen-class
:name sre.plan.Compiler
:methods [^:static [makeConstraintLookupFromTargetsAndBounds
[Iterable Iterable] ConstraintLookup]]))
我正在使用 nebula-clojure
插件和 Gradle 进行 AOT 编译。编译器在遇到 ns 声明时发出错误:
> Task :sre:compileClojure
Exception in thread "main" java.lang.ClassNotFoundException: java.lang.ConstraintLookup, compiling:(sre/plan/compiler.clj:1:1)
类似地,在方法声明中使用完全限定的 sre.plan.dsl.constraint.Constraint
时,我得到:
Exception in thread "main" java.lang.ClassNotFoundException: sre.plan.dsl.constraint.ConstraintLookup, compiling:(sre/plan/compiler.clj:1:1)
这里有什么问题?我迷路了。
更新:
引用的 ns 如下所示:
(ns sre.plan.dsl.constraint
(:require [clojure.set :refer :all]
[clojure.algo.generic.functor :refer :all]))
(defrecord ConstraintLookup [free bound])
更新:
在我看来,在 gen-class 中,无论如何都必须使用完全限定的 class 名称。但是我仍然不明白为什么具有完全限定名称的版本不起作用。
ns
宏中的 :gen-class
指令很可能无法引用作为相同形式的 :require
的副作用生成的 类。 ns
宏发出的代码在调用任何 require
之前调用 gen-class
。因此,调用 gen-class
时所需的名称空间尚未编译。 gen-class
在 defrecord
中的任何 类 生成之前被调用。
可以看到 ns
的行为 in the source code 并且在使用 macroexpand
的 repl 中也可以看到:
(clojure.pprint/pprint (macroexpand '(ns sre.plan.compiler
(:require
[sre.plan.dsl.constraint :as constraint])
(:import (sre.plan.dsl.constraint ConstraintLookup))
(:gen-class
:name sre.plan.Compiler
:methods [^:static [makeConstraintLookupFromTargetsAndBounds
[Iterable Iterable] ConstraintLookup]]))))
;; (do
;; (clojure.core/in-ns 'sre.plan.compiler)
;; (clojure.core/with-loading-context
;; (clojure.core/gen-class
;; :name
;; "sre.plan.compiler"
;; :impl-ns
;; sre.plan.compiler
;; :main
;; true
;; :name
;; sre.plan.Compiler
;; :methods
;; [[makeConstraintLookupFromTargetsAndBounds
;; [Iterable Iterable]
;; ConstraintLookup]])
;; (clojure.core/refer 'clojure.core)
;; (clojure.core/require '[sre.plan.dsl.constraint :as constraint])
;; (clojure.core/import '(sre.plan.dsl.constraint ConstraintLookup)))
;; (if
;; (.equals 'sre.plan.compiler 'clojure.core)
;; nil
;; (do
;; (clojure.core/dosync
;; (clojure.core/commute
;; @#'clojure.core/*loaded-libs*
;; clojure.core/conj
;; 'sre.plan.compiler))
;; nil)))
要解决此问题,我们可以在 ns
之后调用 gen-class
。例如:
(ns sre.plan.compiler
(:require
[sre.plan.dsl.constraint :as constraint])
(:import (sre.plan.dsl.constraint ConstraintLookup)))
(gen-class
:impl-ns
sre.plan.compiler
:main
true
:name
sre.plan.Compiler
:methods
[[makeConstraintLookupFromTargetsAndBounds
[Iterable Iterable]
sre.plan.dsl.constraint.ConstraintLookup]])
我在 sre.plan.dsl.constraint
命名空间中有一个名为 ConstraintLookup
的 defrecord
。
我想在 sre.plan.compiler
命名空间的 gen-class
方法中使用其生成的 class:
(ns sre.plan.compiler
(:require
[sre.plan.dsl.constraint :as constraint])
(:import (sre.plan.dsl.constraint ConstraintLookup))
(:gen-class
:name sre.plan.Compiler
:methods [^:static [makeConstraintLookupFromTargetsAndBounds
[Iterable Iterable] ConstraintLookup]]))
我正在使用 nebula-clojure
插件和 Gradle 进行 AOT 编译。编译器在遇到 ns 声明时发出错误:
> Task :sre:compileClojure
Exception in thread "main" java.lang.ClassNotFoundException: java.lang.ConstraintLookup, compiling:(sre/plan/compiler.clj:1:1)
类似地,在方法声明中使用完全限定的 sre.plan.dsl.constraint.Constraint
时,我得到:
Exception in thread "main" java.lang.ClassNotFoundException: sre.plan.dsl.constraint.ConstraintLookup, compiling:(sre/plan/compiler.clj:1:1)
这里有什么问题?我迷路了。
更新:
引用的 ns 如下所示:
(ns sre.plan.dsl.constraint
(:require [clojure.set :refer :all]
[clojure.algo.generic.functor :refer :all]))
(defrecord ConstraintLookup [free bound])
更新:
在我看来,在 gen-class 中,无论如何都必须使用完全限定的 class 名称。但是我仍然不明白为什么具有完全限定名称的版本不起作用。
ns
宏中的 :gen-class
指令很可能无法引用作为相同形式的 :require
的副作用生成的 类。 ns
宏发出的代码在调用任何 require
之前调用 gen-class
。因此,调用 gen-class
时所需的名称空间尚未编译。 gen-class
在 defrecord
中的任何 类 生成之前被调用。
可以看到 ns
的行为 in the source code 并且在使用 macroexpand
的 repl 中也可以看到:
(clojure.pprint/pprint (macroexpand '(ns sre.plan.compiler
(:require
[sre.plan.dsl.constraint :as constraint])
(:import (sre.plan.dsl.constraint ConstraintLookup))
(:gen-class
:name sre.plan.Compiler
:methods [^:static [makeConstraintLookupFromTargetsAndBounds
[Iterable Iterable] ConstraintLookup]]))))
;; (do
;; (clojure.core/in-ns 'sre.plan.compiler)
;; (clojure.core/with-loading-context
;; (clojure.core/gen-class
;; :name
;; "sre.plan.compiler"
;; :impl-ns
;; sre.plan.compiler
;; :main
;; true
;; :name
;; sre.plan.Compiler
;; :methods
;; [[makeConstraintLookupFromTargetsAndBounds
;; [Iterable Iterable]
;; ConstraintLookup]])
;; (clojure.core/refer 'clojure.core)
;; (clojure.core/require '[sre.plan.dsl.constraint :as constraint])
;; (clojure.core/import '(sre.plan.dsl.constraint ConstraintLookup)))
;; (if
;; (.equals 'sre.plan.compiler 'clojure.core)
;; nil
;; (do
;; (clojure.core/dosync
;; (clojure.core/commute
;; @#'clojure.core/*loaded-libs*
;; clojure.core/conj
;; 'sre.plan.compiler))
;; nil)))
要解决此问题,我们可以在 ns
之后调用 gen-class
。例如:
(ns sre.plan.compiler
(:require
[sre.plan.dsl.constraint :as constraint])
(:import (sre.plan.dsl.constraint ConstraintLookup)))
(gen-class
:impl-ns
sre.plan.compiler
:main
true
:name
sre.plan.Compiler
:methods
[[makeConstraintLookupFromTargetsAndBounds
[Iterable Iterable]
sre.plan.dsl.constraint.ConstraintLookup]])