使用Clojure在Java对象上调用方法列表

时间:2016-07-11 15:04:25

标签: clojure clojure-java-interop

我有一个我想要转换为不可变Java POJO的值列表。使用构建器模式生成Java POJO。

我的清单是:

[49.0 11.1 150.0]

在Java中,我的POJO将构造如下:

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

我想在Clojure中创建它我会首先zipmap使用需要使用的方法的值,然后我可以reduce-kv所有我需要的Java值:

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

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

我现在的问题是我没有达到我的期望。函数poslist->map返回预期值:

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

但是reduce-kv只返回我的最后一个值:

150.0

为什么我不回复构建器,然后我可以应用.build方法?我曾期望reduce-kv与以下代码具有相同的结果,返回我期望的结果:

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

由于reduce-kv函数返回一个双精度,以下调用.build失败

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

BTW:我将方法映射到列表值的原因是,我必须设置的实际字段列表比示例中的更长。在保留基本问题的同时,我删除了示例以使其更具可读性。

1 个答案:

答案 0 :(得分:3)

虽然Clojure符号为act as functions,但它们与任何具有相同名称的函数无关:

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

所以问题基本上就是根本没有调用java方法。要修复它,请使用memfn包装iterop方法:

['.latitude '.longitude '.altitude]

->

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

或者,正如@noisesmith建议的那样,使用clojure函数:

->

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