2010-09-10 26 views
15

Conozco los conceptos básicos de la interoperabilidad de clojure/java: llamar a java desde clojure y viceversa. Sin embargo, no pude devolver una colección mecanografiada de clojure a java. Estoy tratando de ver algo de esa naturaleza List<TypedObject> del código java que está llamando a clojure.¿Cómo pasar una colección tipeada de clojure a java?

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

Consideremos que estoy escribiendo una API usando clojure, que ha de ser distribuido como un archivo JAR, para ser utilizado desde java. Mi pregunta era realmente ¿qué pasar en lugar de ???? preguntas marca arriba dentro de: gen-class para AOT, de modo que un programador que escribe un fragmento de código en java usando mi api, puede tener la terminación intellisense/código apropiada (es decir: createListofTypedObjects() returns List<TypedObject>) desde eclipse por ejemplo.

+0

un pequeño ejemplo del código java que llama a clojure realmente me ayudaría a responder esto :) –

+0

Gracias Alex y Stuart por tus respuestas. Tienen perfecto sentido, pero no exactamente lo que estaba buscando. Con suerte, mi pregunta ahora es menos ambigua. – user258030

Respuesta

20

Los demás tienen razón en que Clojure no garantiza los tipos de elementos en las colecciones devueltas, etc. (En realidad, la JVM tampoco garantiza los tipos de elementos en las colecciones, eso es manejado enteramente por javac)

Sin embargo, puedo ver el valor de proporcionar una API a otros programadores Java que especifica una interfaz que declara que los valores devueltos (o parámetros) se han parametrizado de varias maneras; esto es especialmente atractivo si uno está buscando usar Clojure en un entorno Java existente sin hacer olas.

Este momento requiere un proceso de dos pasos:

  • definir una interfaz independiente (en Java!) Que especifica los tipos parametrizados como desee
  • definir su gen-class espacio de nombres (o proxy o reify ejemplo) tales que implementa la interfaz

(Clojure proporciona una forma definterface que permitirá evitar la definición de interfaz de Java por separado, pero definterface, al igual que el resto de Clojure, no proporciona la especificación de tipos parametrizados. Tal vez algún día ... :-))

p.

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

y luego el espacio de nombres de clase GEN:

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

Cuando los usuarios crean instancias de FooImpl, por ejemplo, que voy obtener el código completo que indica que el método devuelve List<TypedObject> en lugar de Object o el tipo List no parametrizado.

Si está utilizando herramientas de compilación de herramientas (por ejemplo, maven, gradle o hormiga configurada correctamente), puede colocar la interfaz Java en su proyecto Clojure y se tendrá en cuenta la dependencia entre idiomas.

+0

V respuesta útil. Es clave proporcionar definiciones propiamente tipadas para ejecutar en Java env. Rara vez los tipos aparecen después de todo, ya que la mayoría del trabajo implica colecciones y, por lo general, queremos especificar qué contienen. – javadba

11

Si está intentando pasar algo como List<String> a un método Java, entonces no tiene que preocuparse por ello. El parámetro tipo (por ejemplo, String) solo lo utiliza el compilador javac, por lo que cualquier List funcionará perfectamente en el tiempo de ejecución.

Por otro lado, si usted está tratando de pasar una matriz de un determinado tipo de objeto (por ejemplo, String[]), entonces usted puede utilizar las distintas funciones: -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> 
10

Usted no necesita preocuparse por los genéricos (colecciones tipadas) en Clojure. Los genéricos simplemente son sugerencias de tipo al compilador de Java. En un programa Java en ejecución, List<String> es efectivamente el mismo que List<Object>.

Así, por ejemplo, un vector Clojure que contiene cadenas ya es un List<String> sin necesidad de conversión.

+1

No es cierto. Diría más precisamente que, por lo general, no necesita preocuparse por las colecciones escritas a máquina en Clojure. Debido a que esta pregunta trata específicamente con la interoperabilidad de Java, es importante señalar que la colección de entrega puede volverse en algún momento a un método de Java. En este caso, el tipo de elementos en la colección puede ser importante si el nombre del método está sobrecargado tomando colecciones con diferentes tipos de elementos. Entiendo que esto puede ser oscuro e inusual ... pero existe. – Jason

+0

No conozco una manera de denotar instancias precisas de genéricos en Clojure. Por ejemplo, uno puede escribir 'java.lang.ArrayList' pero no' java.langArrayList '. Si tienes razón, @Jason, ¿esta carencia podría ser un agujero en la interoperabilidad Clojure-Java? ¿Podría haber API en Java que no se puedan llamar desde Clojure porque los tipos de colección covariantes no son denotables? Las respuestas arriba y abajo sugieren que no, es decir, que estamos bien, al menos por ahora. –

Cuestiones relacionadas