Clojure — проблемы с синтаксисом для доступа к gen-классу из другого пространства имен

Кажется, что lein непредсказуем в том, как он перекомпилирует код. У меня есть файл класса gen в одном каталоге, я пытаюсь получить к нему доступ в другом. Например, учитывая этот gen-класс:

(ns a.Target
    (:gen-class
     :state state
     :init  init
     :constructors {[String String] []}))

(defn -init
  [m1  m2]
  [[]  (atom {"A" m1 "B" m2})])

(defn -deref
  [this]
  @(.state this))

И попытка получить доступ к этому из другого пространства имен сводится к попытке случайных вариантов 1, 2,3:

(ns b.runner
    (:require [a.Target  ] :as Target) ;1
    (:import '(a Target))              ;2
)

(compile 'a.Target) ;3

Кажется, что нет синтаксиса, который распознает «Target» вместо «a.Target», поэтому явно что-то не так в том, как я обращаюсь к gen-классу. Это проблема, потому что я пытаюсь получить доступ к нашим guice-инжекторам, используя аннотированные методы провайдера, а синтаксис аннотации, похоже, не принимает ни полные, ни простые спецификации класса:

(definterface TargetProvider (^a.Target getTarget [this] ))
=> Exception in thread "main" java.lang.UnsupportedOperationException: nth not supported on this type:

или упрощенные:

(definterface TargetProvider (^Target getTarget [this] ))
=> Can't find class java.lang.Target

person Steve B.    schedule 27.01.2014    source источник
comment
У вас опечатка в форме ns: (:require [a.Target :as Target]), а не (:require [a.Target ] :as Target).   -  person omiel    schedule 27.01.2014
comment
Чего вы на самом деле пытаетесь достичь здесь?   -  person ponzao    schedule 27.01.2014


Ответы (1)


Выражение ns должно быть (ns b (:import a.Target)), нет необходимости использовать :require для импортируемого класса. Так как ns является макросом, все символы в :require, :use и других параметрах не оцениваются, поэтому нет необходимости заключать их в кавычки. Со следующим объявлением ns ваше выражение definterface должно работать.

(ns b
  (:import a.Target))

(definterface TargetProvider [^a.Target getTarget []])

(->> b.TargetProvider .getMethods seq)
;= (#<Method public abstract a.Target b.TargetProvider.getTarget()>)

ИЗМЕНИТЬ

Это код для прокси-сервера, использующего интерфейс TargetProvider, определенный выше, который, как я думаю, вы просили в комментариях.

Обратите внимание, что я также изменил объявление метода интерфейса getTarget, удалив аргумент this, так как он фактически не получает ссылку на текущий экземпляр. При использовании proxy имеется неявно связанный this локальный (дополнительную информацию см. здесь).

(let [x (proxy [TargetProvider] []
          (getTarget [] (Target. "x" "y")))]
  (.getTarget x))
person juan.facorro    schedule 27.01.2014
comment
Спасибо, это полезно. Не хочу просить большего, но можете ли вы добавить пример прокси, который использует этот интерфейс? Когда я добавляю метод, он, похоже, не воспринимает аннотацию. Попытка, например. ( ^{Предоставляет {}} ^a.Target getTarget [это] ( ... )) - person Steve B.; 28.01.2014
comment
Спасибо за правку - ценю. Однако этот синтаксис дает: Исключение в потоке main java.lang.IllegalArgumentException: не найден соответствующий метод: getMethod для класса в clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:53) ... Все еще гадая с синтаксисом, я Напишу, если смогу заставить эту чертову штуку работать. - person Steve B.; 28.01.2014
comment
Я не уверен, чего вы пытаетесь достичь, но упомянутая вами ошибка не выглядит так, как будто она имеет какое-то отношение к синтаксису. Пожалуйста, добавьте код для всего ns, который вызывает ошибку, которую вы разместили в предыдущем комментарии, и мы возьмем ее оттуда. - person juan.facorro; 28.01.2014