简体   繁体   English

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

[英]How to pass a typed collection from clojure to java?

I know the basics of clojure/java interop: calling java from clojure and vice versa. 我知道clojure / java interop的基础知识:从clojure调用java,反之亦然。 However, I was not able to return a typed collection from clojure to java. 但是,我无法将clojure中的类型集合返回给java。 I am trying to see something of that nature List<TypedObject> from the java code which is calling into clojure. 我试图从调用clojure的java代码中看到一些自然的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] ????])

Let us consider that I am writing an API using clojure, which is to be distributed as a jar file, to be used from java. 让我们考虑一下,我正在使用clojure编写一个API,它将作为jar文件分发,以便在java中使用。 My question was really how to what to pass in place of the ???? 我的问题是如何通过代替???? questions marks above inside the :gen-class for AOT, so that a programmer writing a piece of code in java using my api, can have the appropriate intellisense / code completion (ie: createListofTypedObjects() returns List<TypedObject> ) from within eclipse for example. 上面的问题标记在:AOT的gen类中,以便程序员使用我的api在java中编写一段代码,可以从eclipse中获得相应的intellisense / code completion(即: createListofTypedObjects() returns List<TypedObject> )例如。

The others are right that Clojure doesn't ensure the types of elements in returned collections, etc. (Actually, the JVM doesn't ensure the types of elements in collections, either – that's handled entirely by javac.) 其他是正确的,Clojure不能确保返回集合中的元素类型等。(实际上,JVM也不能确保集合中元素的类型 - 完全由javac处理。)

However, I can see the value of providing an API to other Java programmers that specifies an interface that declares that return values (or parameters) parameterized in various ways; 但是,我可以看到为其他Java程序员提供API的价值,这些程序员指定了一个接口,该接口声明以各种方式参数化的返回值(或参数); this is especially attractive if one is looking to use Clojure in an existing Java environment without making waves. 如果想要在现有的Java环境中使用Clojure而不制造波浪,这一点尤其具有吸引力。

This currently requires a two step process: 这目前需要两个步骤:

  • define a separate interface (in Java!) that specifies the parameterized types as you like 定义一个单独的接口(在Java中!),它可以根据需要指定参数化类型
  • define your gen-class namespace (or proxy or reify instance) such that it implements that interface 定义您的gen-class名称空间(或proxyreify实例),以便它实现该接口

(Clojure does provide a definterface form that would allow you to avoid the separate Java interface definition, but definterface , just like the rest of Clojure, does not provide for specifying parameterized types. Maybe someday... :-)) (Clojure确实提供了一个允许你避免单独的Java接口定义的definterface形式,但是definterface ,就像Clojure的其余部分一样,没有提供指定参数化类型。也许有一天... :-))

eg 例如

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

and then your gen-class namespace: 然后你的gen-class命名空间:

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

When your users create instances of FooImpl , they'll eg get code completion indicating that the method returns List<TypedObject> rather than Object or the unparameterized List type. 当您的用户创建FooImpl实例时,他们将例如获得代码完成,指示该方法返回List<TypedObject>而不是Object或未参数化的List类型。

If you're using sane build tools (eg maven , gradle, or properly-configured ant), then you can put the Java interface in your Clojure project, and the cross-language dependency will be taken care of. 如果您正在使用理智的构建工具(例如maven ,gradle或正确配置的ant),那么您可以将Java接口放在Clojure项目中,并且将考虑跨语言依赖性。

If you're trying to pass something like List<String> to a java method, then you don't need to worry about it. 如果您尝试将类似List<String>传递给java方法,那么您不必担心它。 The type parameter (eg, String ) is only used to by the javac compiler, so any List will work just fine at runtime. 类型参数(例如, String )仅用于javac编译器,因此任何List在运行时都可以正常工作。

On the other hand if you're trying to pass an array of a particular object type (eg, String[] ), then you can use the various -array functions: 另一方面,如果您尝试传递特定对象类型的数组(例如, 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>

You don't need to worry about generics (typed collections) in Clojure. 您不必担心Clojure中的泛型(类型集合)。 Generics are really just type hints to the Java compiler. 泛型实际上只是Java编译器的类型提示。 In a running Java program, List<String> is effectively the same as List<Object> . 在正在运行的Java程序中, List<String>实际上与List<Object>相同。

So, for example, a Clojure vector containing Strings is already a List<String> with no conversion needed. 因此,例如,包含字符串的Clojure向量已经是List<String> ,不需要转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM