I have a list of values I want to convert to an immutable Java POJO. The Java POJO gets generated using the builder pattern.
The list I have is:
[49.0 11.1 150.0]
In Java my POJO would get constructed like this:
Position.builder().latitude(49.0).longitude(11.1).altitude(150.0).build()
I thought to create it in Clojure I would first zipmap
the values with the methods that need to be used and then I could reduce-kv
everything to the Java value I need:
(defn poslist->map [list]
(zipmap ['.latitude '.longitude '.altitude]
list))
(.build (reduce-kv #(%2 %1 %3)
(pkg.Position/builder)
(poslist->map list)))
My problem now is that I don't get what I expect. The function poslist->map
returns the expected value:
{.latitude 49.0, .longitude 11.1, .altitude 150.0}
But the reduce-kv
just returns the last value I have:
150.0
Why don't I get back the builder on which I then can apply the .build
method? I had expected that the reduce-kv
to have the same result as the following code that returns what I expect:
(.build (.altitude (.longitude (.latitude (pkg.Position/builder) 150.0) 11.1) 49.0))
And as the reduce-kv
function returns a double the following call of .build
failes with
No matching field found: build for class java.lang.Double
BTW: The reason I am mapping the methods to the list values is, that the actual list of fields I have to set is longer as in the example. I stripped down the example to be more readable while retaining my basic problem.
While Clojure symbols act as functions, they are not connected with functions with the same name in any way:
> ('.add (java.util.ArrayList.) 1)
1
> ('first [1 2 3])
nil
> ('conj [1 2] 3)
3
So the issue, basically, is that java methods are not called at all. To fix it wrap your iterop methods with memfn
:
['.latitude '.longitude '.altitude]
->
[(memfn latitude val) (memfn longitude val) (memfn altitude val)]
or, as @noisesmith suggested, with clojure functions:
->
[#(.latitude %1 %2) #(.longitude %1 %2) #(.altitude %1 %2)]