ClassNotFoundException при использовании экземпляра? на типе дезаписи в Clojure

Я написал функцию, которая выбирает только те ключи карты, которые названы в определенной схеме:

(ns foo.schema
  (:require [schema.core :as s]))

(defn select-schema
  "Given a schema and a map m, selects only the keys of m that are named in the schema."
  [m schema]
  (let [optional? #(instance? schema.core.OptionalKey %)
        wildcard? #(= s/Keyword %)]
    (if (some wildcard? (keys schema))
      m  ; the schema allows any keyword as a key, so just return the map
      (let [ks (->> schema keys (map #(if (optional? %) (:k %) %)))]
        (select-keys m ks)))))

Это отлично работает в моих модульных тестах:

(testing "Required key and wildcard"
    (let [schema {:foo s/Str, s/Keyword s/Any}]
      (is (= {:foo "Yup", :bar 42, :baz true} (select-schema {:foo "Yup", :bar 42, :baz true} schema)))
      (is (= {:foo "Yup", :bar 42} (select-schema {:foo "Yup", :bar 42} schema)))
      (is (= {:foo "Yup"} (select-schema {:foo "Yup"} schema)))))

Однако, когда я использую foo.schema/select-schema в совершенно отдельном проекте (например, lein install в моем проекте foo, чтобы создать банку, вставить ее в мой ~/.m2/repository и назвать как зависимость), я получаю ClassNotFoundException:

Exception in thread "main" java.lang.ExceptionInInitializerError, compiling:(insurrection/test/handler.clj:1:1)
    at clojure.lang.Compiler.load(Compiler.java:7142)
    ...
Caused by: java.lang.ExceptionInInitializerError
    at foo.schema__init.load(Unknown Source)
    at foo.schema__init.<clinit>(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    ...
Caused by: java.lang.ClassNotFoundException: schema.core.OptionalKey
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    ...

Я просмотрел исходный код Prismatic Schema и обнаружил, что OptionalKey — это тип дезаписи. Небольшое гугление показало, что defrecord генерирует класс Java, который иногда необходимо импортировать после запроса определяющего его пространства имен, но попытка сделать это в проекте, содержащем foo.schema, не имеет никакого значения: он работает в модульных тестах, но не работает в другом проекте, который использует foo в качестве зависимости.


person Josh Glover    schedule 15.10.2014    source источник


Ответы (1)


Вы импортировали schema.core как s. Если это именно тот код, который вы используете, вам, вероятно, следует использовать #(instance? s/OptionalKey %) в качестве функции optional?.

Не говоря уже о том, что schema является локальной переменной (аргументом) в select-schema.

person Max Noel    schedule 15.10.2014
comment
instance? работает с типами Java, поэтому он не знает пространств имен Clojure и псевдонимов с require ... :as s. Я не понимаю вашего второго утверждения о том, что schema является локальной переменной (привязка AKA) в select-schema. Это вызывает проблемы? - person Josh Glover; 15.10.2014
comment
Неважно, я идиот. В этом случае ваша проблема, вероятно, заключается в том, что любая банка, определяющая schema.core.OptionalKey, не находится в вашем пути к классам при запуске отдельного проекта. - person Max Noel; 15.10.2014
comment
У вас есть идеи, почему это может быть? У меня есть prismatic/schema, определенная как зависимость как в проекте foo (содержащем указанную выше функцию), и в отдельном проекте, который зависит от foo. - person Josh Glover; 15.10.2014