2

I'm following this example to initiate a Stream.Builder:

http://www.java2s.com/Tutorials/Java/java.util.stream/Stream.Builder/Stream.Builder.build_.htm

(def b (doto (Stream/builder)
          (.accept "a")
          (.accept "b")
          (.accept "c")
          (.accept "d")
          (.accept "e")))

However, I'm getting this:

Unhandled java.lang.IncompatibleClassChangeError
 Method
 java.util.stream.Stream.builder()Ljava/util/stream/Stream$Builder;
 must be InterfaceMethodref constant

Is there anything I'm missing?

7
  • 1
    String or Stream builder? -> I'm following this example to initiate a String.Builder: Commented Mar 30, 2018 at 12:25
  • Stream.Builder. Thanks for the catch. Commented Mar 30, 2018 at 12:28
  • Also did you check your Stream class path? (import java.util.stream.Stream) I have no problems Commented Mar 30, 2018 at 12:28
  • I'm using java 9. I'll try java 8 Commented Mar 30, 2018 at 12:29
  • 1
    Yeah try that I'm using java and clojure 8 Commented Mar 30, 2018 at 12:29

2 Answers 2

3

quick research led me to this issue: https://dev.clojure.org/jira/browse/CLJ-2284

so the workaround is as mentioned there:

(import 'java.util.stream.Stream)

(defmacro interface-static-call
  [sym & argtypes]
  `(let [m# (.getMethod ~(symbol (namespace sym))
                        ~(name sym)
                        (into-array Class ~argtypes))]
     (fn [& args#]
       (.invoke m# nil (to-array args#)))))

(doto ((interface-static-call Stream/builder))
  (.accept "a")
  (.accept "b")
  (.accept "c")
  (.accept "d")
  (.accept "e"))

;;=> #object[java.util.stream.Streams$StreamBuilderImpl 0x121300ed "java.util.stream.Streams$StreamBuilderImpl@121300ed"]

works for me on java 9

so i guess we should wait for a fix in clojure.

Sign up to request clarification or add additional context in comments.

Comments

1

Very helpful, thanks, for those of us stuck on Clojure 8 but needing to use a Java newer than 1.8.

For what it's worth, the macro in the answer above won't work if argtypes is not empty, because the macro as written constructs an unquoted list of classes as the third parameter to .getMethod, and Clojure tries to invoke the first class in the list as an IFn. I needed to redefine the macro as:

(defmacro interface-static-call
  [sym & argtypes]
  `(let [m# (.getMethod ~(symbol (namespace sym))
                        ~(name sym)
                        (into-array Class ~(into [] argtypes)))]
     (fn [& args#]
       (.invoke m# nil (to-array args#)))))

Comments

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.