1

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.

1 Answer 1

4

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)]
Sign up to request clarification or add additional context in comments.

2 Comments

there's no situation currently where (memfn foo) is preferable to #(.foo %)
Thank you both, that works! Just one note: to match exactly my question, the created function takes two parameters (the builder instance and the value to set). Therefore it's either (memfn latitude val) or #(.latitude %1 %2).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.