I know the basics of clojure/java interop: calling java from clojure and vice versa. However, I was not able to return a typed collection from clojure to java. I am trying to see something of that nature List<TypedObject>
from the java code which is calling into 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] ????])
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. 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 (i.e.: createListofTypedObjects() returns List<TypedObject>
) from within eclipse for example.
If you're trying to pass something like
List<String>
to a java method, then you don't need to worry about it. The type parameter (e.g.,String
) is only used to by the javac compiler, so anyList
will work just fine at runtime.On the other hand if you're trying to pass an array of a particular object type (e.g.,
String[]
), then you can use the various-array
functions:You don't need to worry about generics (typed collections) in Clojure. Generics are really just type hints to the Java compiler. In a running Java program,
List<String>
is effectively the same asList<Object>
.So, for example, a Clojure vector containing Strings is already a
List<String>
with no conversion needed.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.)
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; this is especially attractive if one is looking to use Clojure in an existing Java environment without making waves.
This currently requires a two step process:
gen-class
namespace (orproxy
orreify
instance) such that it implements that interface(Clojure does provide a
definterface
form that would allow you to avoid the separate Java interface definition, butdefinterface
, just like the rest of Clojure, does not provide for specifying parameterized types. Maybe someday... :-))e.g.
and then your gen-class namespace:
When your users create instances of
FooImpl
, they'll e.g. get code completion indicating that the method returnsList<TypedObject>
rather thanObject
or the unparameterizedList
type.If you're using sane build tools (e.g. 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.