如何将类型化集合从 clojure 传递到 java?

2022-09-02 23:37:02

我知道 clojure/java 互操作的基础知识:从 clojure 调用 java,反之亦然。但是,我无法将类型化集合从clojure返回到java。我试图从java代码中看到这种性质的东西,它正在调用clojure。List<TypedObject>

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] ????])

让我们考虑一下,我正在使用clojure编写一个API,它将作为jar文件分发,从java使用。我的问题实际上是如何通过什么来代替????上面的问号在AOT的:gen-class中,以便程序员使用我的api在java中编写一段代码,例如,可以从eclipse内部获得适当的智能感知/代码完成(即:)。createListofTypedObjects() returns List<TypedObject>


答案 1

其他人是对的,Clojure没有确保返回集合中的元素类型等(实际上,JVM也没有确保集合中的元素类型 - 这完全由javac处理。

但是,我可以看到向其他Java程序员提供API的价值,该API指定了一个接口,该接口声明以各种方式参数化的返回值(或参数);如果希望在现有的Java环境中使用Clojure而不会引起波澜,这尤其有吸引力。

这目前需要两个步骤:

  • 定义一个单独的接口(在Java中!),该接口根据需要指定参数化类型
  • 定义命名空间(或或实例),以便它实现该接口gen-classproxyreify

(Clojure 确实提供了一种形式,允许您避免单独的 Java 接口定义,但是,就像 Clojure 的其余部分一样,它没有提供指定参数化类型。也许有一天... :-))definterfacedefinterface

例如:

public interface IFoo {
    List<TypedObject> createListOfTypedObjects ();
}

然后是你的 gen-class 命名空间:

(ns your.ns.FooImpl
  (:gen-class
    :implements [IFoo]))
(defn -createListOfTypedObjects
  []
  [typedObj1, typedObj2, typedObj3])

例如,当您的用户创建 的实例时,他们将获得代码完成,指示该方法返回而不是或非参数化类型。FooImplList<TypedObject>ObjectList

如果您使用的是 sane 构建工具(例如 maven、gradle 或正确配置的 ant),那么您可以将 Java 接口放在 Clojure 项目中,跨语言依赖关系将得到处理。


答案 2

如果你试图将类似的东西传递给java方法,那么你不需要担心它。类型参数(例如,)仅由javac编译器使用,因此任何参数在运行时都可以正常工作。List<String>StringList

另一方面,如果您尝试传递特定对象类型的数组(例如,),则可以使用各种函数: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>

推荐