I have a defrecord
called ConstraintLookup
in sre.plan.dsl.constraint
namespace.
I want to use its generated class in a gen-class
method placed on the sre.plan.compiler
namespace:
(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]]))
I am AOT compiling with nebula-clojure
plugin and Gradle. The compiler emits an error when it encounters the ns declaration:
> Task :sre:compileClojure
Exception in thread "main" java.lang.ClassNotFoundException: java.lang.ConstraintLookup, compiling:(sre/plan/compiler.clj:1:1)
Similarly when using fully qualified sre.plan.dsl.constraint.Constraint
in the method declaration I get:
Exception in thread "main" java.lang.ClassNotFoundException: sre.plan.dsl.constraint.ConstraintLookup, compiling:(sre/plan/compiler.clj:1:1)
What is the problem here? I am lost.
UPDATE:
The referenced ns looks like this:
(ns sre.plan.dsl.constraint
(:require [clojure.set :refer :all]
[clojure.algo.generic.functor :refer :all]))
(defrecord ConstraintLookup [free bound])
UPDATE:
It seems to me that in gen-class you have to use fully qualified class names no matter what. However I still don't understand why doesn't the version with the fully qualified name work.
There is a good chance the :gen-class
directive inside the ns
macro cannot refer to classes generated as a side effect of :require
in the same form. The code emitted by the ns
macro calls gen-class
before calling any of the require
s. Thus the required namespaces are not yet compiled when gen-class
is called. gen-class
is called before any classes from defrecord
are generated.
The behavior of ns
can be seen in the source code and also in the repl using macroexpand
:
(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)))
To work around the problem, we can call gen-class
after ns
. For example:
(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]])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With