2010-09-10 17 views
15

Conosco le basi di clojure/java interop: chiama java da clojure e viceversa. Tuttavia, non ero in grado di restituire una raccolta tipizzata da clojure a java. Sto cercando di vedere qualcosa di quella natura List<TypedObject> dal codice java che sta chiamando in clojure.Come passare una collezione tipizzata da 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] ????]) 

Consideriamo che sto scrivendo un'API utilizzando clojure, che deve essere distribuito come un file jar, per essere utilizzato da Java. La mia domanda era davvero come cosa passare al posto del ???? questioni di marchi di cui sopra all'interno del: Gen-classe per AOT, in modo che un programmatore che scrive un pezzo di codice in Java utilizzando il mio api, può avere il completamento intellisense/codice appropriato (cioè .: createListofTypedObjects() returns List<TypedObject>) dall'interno di Eclipse per esempio.

+0

un breve esempio del codice java che chiama clojure mi aiuterebbe molto anser questo :) –

+0

Grazie Alex e Stuart per le vostre risposte. Hanno perfettamente senso, ma non proprio quello che stavo cercando. Spero che la mia domanda ora sia meno ambigua. – user258030

risposta

20

Gli altri hanno ragione che Clojure non garantisce i tipi di elementi nelle raccolte restituite, ecc. (In realtà, la JVM non garantisce i tipi di elementi nelle raccolte - sia gestita interamente da javac.)

Tuttavia, posso vedere il valore di fornire un'API per altri programmatori Java che specifica un'interfaccia che dichiara che i valori di ritorno (o parametri) parametrizzati in vari modi; questo è particolarmente interessante se si sta cercando di usare Clojure in un ambiente Java esistente senza fare ondate.

Questo momento richiede un processo in due fasi:

  • definire un'interfaccia separata (in Java!) Che specifica i tipi parametrizzati come ti piace
  • definire il tuo gen-class spazio dei nomi (o proxy o reify esempio) quali che implementa quell'interfaccia

(Clojure fornisce un modulo definterface che consente di evitare la definizione di interfaccia Java separata, ma definterface, proprio come il resto di Clojure, non prevede la specifica dei tipi parametrizzati. Forse un giorno ... :-))

ad es.

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

e poi il Gen-class namespace:

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

Quando gli utenti di creare istanze di FooImpl, faranno per esempio ottenere il completamento del codice che indica che il metodo restituisce List<TypedObject> anziché Object o il tipo non parametrizzato List.

Se si utilizzano strumenti di generazione normale (ad esempio maven, gradle o formica configurata correttamente), è possibile inserire l'interfaccia Java nel progetto Clojure e la dipendenza tra lingue sarà gestita.

+0

V risposta utile. È fondamentale fornire definizioni corrette fortemente tipizzate per l'esecuzione in java env. Raramente i tipi di fare non appaiono dopotutto poiché la maggior parte del lavoro riguarda le raccolte e solitamente vogliamo specificare cosa contengono. – javadba

11

Se si sta tentando di passare qualcosa come List<String> a un metodo java, non è necessario preoccuparsene. Il parametro type (ad es., String) è utilizzato solo dal compilatore javac, quindi qualsiasi List funzionerà correttamente in fase di esecuzione.

D'altra parte, se si sta cercando di passare un array di un particolare tipo di oggetto (ad esempio, String[]), quindi è possibile utilizzare le varie funzioni: -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

Non è necessario preoccuparsi di generici (raccolte tipizzate) in Clojure. I generici sono in realtà solo suggerimenti per il compilatore Java. In un programma Java in esecuzione, List<String> equivale esattamente a List<Object>.

Quindi, ad esempio, un vettore Clojure contenente stringhe è già un List<String> senza necessità di conversione.

+1

Non vero. Direi più precisamente, tu di solito non devi preoccuparti delle raccolte digitate in Clojure. Poiché questa domanda riguarda specificamente l'interoperabilità di Java, è importante sottolineare che la raccolta di dati può essere restituita a un metodo Java. In questo caso, il tipo di elementi nella raccolta può essere importante se il nome del metodo è sovraccarico e richiede raccolte con tipi di elementi diversi. Capisco che questo possa essere oscuro e non comune ... ma esiste. – Jason

+0

Non conosco un modo per denotare istanze precise di generici in Clojure. Ad esempio, si può scrivere 'java.lang.ArrayList' ma non' java.langArrayList '. Se hai ragione, @Jason, questa mancanza potrebbe essere un buco nell'intervallo Clojure-Java? Potrebbero esserci API in Java che non possono essere richiamate da Clojure perché i tipi di raccolta covarianti non sono denotabili? Le risposte sopra e sotto non suggeriscono, cioè, che stiamo bene, almeno per ora. –

Problemi correlati