You cannot use a class from another namespace in ns: gen-class

I have a defrecord called ConstraintLookup in the sre.plan.dsl.constraint namespace. I want to use its generated class in the gen-class method placed in 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 compile AOT with the nebula-clojure plugin and Gradle. The compiler throws an error when it encounters an 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 the full sre.plan.dsl.constraint.Constraint declaration 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? I am lost.

UPDATE:

The indicated ns are as follows:

 (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 a gen class you should use fully qualified class names no matter what. However, I still do not understand why the version with a fully qualified name does not work.

+5
source share
1 answer

There is a good chance that the :gen-class directive inside the ns macro cannot reference classes created as a side effect :require in the same form. The code emitted by the ns macro calls gen-class before calling any of require s. Thus, the required namespaces have not yet been compiled when the gen-class called. gen-class is called before any classes are created from defrecord .

The behavior of ns can be seen in the source code as well as in repl with 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 get around the problem, we can call the gen-class after ns . For instance:

 (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]]) 
+2
source

Source: https://habr.com/ru/post/1271263/


All Articles