2016-07-11 1 views
0

J'ai une liste de valeurs que je veux convertir en un POJO Java immuable. Le POJO Java est généré à l'aide du modèle de générateur.Appel d'une liste de méthodes sur un objet Java à l'aide de Clojure

La liste que j'ai est:

[49.0 11.1 150.0] 

En Java mon POJO obtiendrait construit comme ceci:

Position.builder().latitude(49.0).longitude(11.1).altitude(150.0).build() 

Je pensais que pour créer dans Clojure Je voudrais d'abord zipmap les valeurs avec les méthodes qui doit être utilisé et puis je pourrais reduce-kv tout à la valeur Java dont j'ai besoin:

(defn poslist->map [list] 
     (zipmap ['.latitude '.longitude '.altitude] 
       list)) 

(.build (reduce-kv #(%2 %1 %3) 
        (pkg.Position/builder) 
        (poslist->map list))) 

Mon problème maintenant est que je ne comprends pas ce que je m'attends. La fonction retourne poslist->map la valeur attendue:

{.latitude 49.0, .longitude 11.1, .altitude 150.0} 

Mais le reduce-kv retourne juste la dernière valeur que j'ai:

150.0 

Pourquoi ne pas récupérer le constructeur sur lequel je peux ensuite appliquer la .build méthode? Je l'avais prévu que le reduce-kv d'avoir le même résultat que le code suivant qui renvoie ce que je pense:

(.build (.altitude (.longitude (.latitude (pkg.Position/builder) 150.0) 11.1) 49.0)) 

Et comme la fonction reduce-kv retourne un double l'appel suivant de .build failes avec

No matching field found: build for class java.lang.Double 

BTW: La raison pour laquelle je suis en train de mapper les méthodes aux valeurs de la liste est que la liste actuelle des champs que je dois définir est plus longue que dans l'exemple. J'ai démonté l'exemple pour être plus lisible tout en conservant mon problème de base.

Répondre

2

Alors que les symboles Clojure act as functions, ils ne sont pas liés à des fonctions avec le même nom de quelque façon que:

> ('.add (java.util.ArrayList.) 1) 
1 
> ('first [1 2 3]) 
nil 
> ('conj [1 2] 3) 
3 

Donc la question, au fond, est que les méthodes Java ne sont pas appelés du tout. Pour fixer envelopper vos méthodes de iterop avec memfn:

['.latitude '.longitude '.altitude] 

-> 

[(memfn latitude val) (memfn longitude val) (memfn altitude val)] 

ou, comme @noisesmith a suggéré, avec des fonctions de Clojure:

-> 

[#(.latitude %1 %2) #(.longitude %1 %2) #(.altitude %1 %2)] 
+1

il n'y a pas de situation actuellement où '(memfn foo)' est préférable de '# (.foo%) ' – noisesmith

+1

Merci à vous deux, cela fonctionne! Juste une note: pour correspondre exactement à ma question, la fonction créée prend deux paramètres (l'instance du générateur et la valeur à définir). Donc c'est soit '(memfn latitude val)' ou '# (. Latitude% 1% 2)'. –

+0

c'est correct. J'ai mis à jour ma réponse. – OlegTheCat