Как передать печатную коллекцию из clojure в java?
Я знаю основы взаимодействия clojure/java: вызов java из clojure и наоборот. Однако я не смог вернуть напечатанную коллекцию из clojure в java. Я пытаюсь увидеть что-то подобное List<TypedObject>
из кода Java, который вызывает в clojure.
Java Object:
public class TypedObject {
private OtherType1 _prop1;
public OtherType1 getProp1() {
return _prop1;
}
public void setProp1(OtherType1 prop1) {
_prop1 = prop1;
}
}
CLojure method:
(defn -createListOfTypedObjects
"Creates and returns a list of TypedObjects"
[input]
;Do work here to create and return list of TypedObjects
[typedObj1, typedObj2, typedObj3])
(:gen-class
:name some.namespace
:methods [createListofTypedObjects[String] ????])
Давайте рассмотрим, что я пишу API с использованием clojure, который должен распространяться в виде jar-файла, который будет использоваться из java. Мой вопрос был действительно, как к тому, чтобы перейти на место???? знаки вопроса выше внутри:gen-class для AOT, так что программист, пишущий кусок кода на Java с использованием моего API, может иметь соответствующий intellisense / завершение кода (то есть: createListofTypedObjects() returns List<TypedObject>
) из затмения, например.
3 ответа
Другие правы в том, что Clojure не обеспечивает типы элементов в возвращаемых коллекциях и т. Д. (На самом деле, JVM также не обеспечивает типы элементов в коллекциях - это полностью обрабатывается javac.)
Однако я вижу ценность предоставления API другим программистам Java, который определяет интерфейс, который объявляет, что возвращаемые значения (или параметры) параметризованы различными способами; это особенно привлекательно, если вы хотите использовать Clojure в существующей среде Java без каких-либо волн.
В настоящее время это требует двухэтапного процесса:
- определить отдельный интерфейс (в Java!), который задает параметризованные типы, как вам нравится
- определить ваш
gen-class
пространство имен (илиproxy
или жеreify
например), так что он реализует этот интерфейс
(Clojure действительно обеспечивает definterface
форма, которая позволит вам избежать отдельного определения интерфейса Java, но definterface
Как и остальная часть Clojure, не предусматривает указание параметризованных типов. Возможно когда-нибудь...:-))
например
public interface IFoo {
List<TypedObject> createListOfTypedObjects ();
}
а затем ваше пространство имен класса gen:
(ns your.ns.FooImpl
(:gen-class
:implements [IFoo]))
(defn -createListOfTypedObjects
[]
[typedObj1, typedObj2, typedObj3])
Когда ваши пользователи создают экземпляры FooImpl
например, они получат завершение кода, указывающее, что метод возвращает List<TypedObject>
скорее, чем Object
или непараметрический List
тип.
Если вы используете нормальные инструменты сборки (например, maven, gradle или должным образом настроенный муравей), то вы можете поместить Java-интерфейс в ваш проект Clojure, и о межъязыковой зависимости позаботятся.
Если вы пытаетесь передать что-то вроде List<String>
к методу Java, тогда вам не нужно беспокоиться об этом. Параметр типа (например, String
) используется только компилятором javac, поэтому любой List
будет хорошо работать во время выполнения.
С другой стороны, если вы пытаетесь передать массив определенного типа объекта (например, String[]
), то вы можете использовать различные -array
функции:
user=> (make-array String 10) ; an empty String array
#<String[] [Ljava.lang.String;@78878c4c>
user=> (into-array ["foo" "bar"]) ; array type inferred from first element
#<String[] [Ljava.lang.String;@743fbbfc>
user=> (into-array Number [1.2 5 7N]) ; explicit type array
#<Number[] [Ljava.lang.Number;@7433b121>
Вам не нужно беспокоиться о дженериках (типизированных коллекциях) в Clojure. Дженерики - это просто подсказки типов для компилятора Java. В работающей Java-программе List<String>
фактически так же, как List<Object>
,
Так, например, вектор Clojure, содержащий строки, уже List<String>
без необходимости конвертации.