From c3c2c8b108c14eae1eb809b38a46fb5aef23e6e6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 10 Oct 2024 20:54:29 +0200 Subject: [PATCH] Clojure 1.12 IFn coercion --- CHANGELOG.md | 1 + deps.edn | 2 +- impl-java/build.clj | 9 +- impl-java/deps.edn | 2 +- .../src/babashka/impl/reify2/interfaces.clj | 1 + project.clj | 2 +- .../babashka/babashka/proxy-config.json | 31 +++ sci | 2 +- src/babashka/impl/classes.clj | 180 +++++++++--------- src/babashka/impl/reify.clj | 1 - test/babashka/interop_test.clj | 11 ++ test/babashka/reify_test.clj | 7 + 12 files changed, 156 insertions(+), 93 deletions(-) create mode 100644 resources/META-INF/native-image/babashka/babashka/proxy-config.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 8db5d0ea..2474a786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ A preview of the next release can be installed from ## Unreleased +- Clojure 1.12 interop: method thunks, FI coercion, array notation - Upgrade SCI reflector based on clojure 1.12 and remove specific workaround for `Thread/sleep` interop - Add `tools.reader.edn/read` diff --git a/deps.edn b/deps.edn index 698182eb..a01ef720 100644 --- a/deps.edn +++ b/deps.edn @@ -20,7 +20,7 @@ "impl-java/src"], :deps {org.clojure/clojure {:mvn/version "1.12.0"}, org.babashka/sci {:local/root "sci"} - org.babashka/babashka.impl.java {:mvn/version "0.1.8"} + org.babashka/babashka.impl.java {:mvn/version "0.1.9"} org.babashka/sci.impl.types {:mvn/version "0.0.2"} babashka/babashka.curl {:local/root "babashka.curl"} babashka/fs {:local/root "fs"} diff --git a/impl-java/build.clj b/impl-java/build.clj index b2688a9c..a543991a 100644 --- a/impl-java/build.clj +++ b/impl-java/build.clj @@ -3,7 +3,7 @@ [clojure.tools.build.api :as b])) (def lib 'org.babashka/babashka.impl.java) -(def version "0.1.8") +(def version "0.1.9") (def class-dir "target/classes") (def basis (b/create-basis {:project "deps.edn"})) (def jar-file (format "target/%s-%s.jar" (name lib) version)) @@ -26,7 +26,12 @@ :lib lib :version version :basis basis - :src-dirs ["src"]}) + :src-dirs ["src"] + :pom-data + [[:licenses + [:license + [:name "MIT License"] + [:url "https://opensource.org/license/mit/"]]]]}) (b/copy-dir {:src-dirs ["src"] :target-dir class-dir}) (b/jar {:class-dir class-dir diff --git a/impl-java/deps.edn b/impl-java/deps.edn index 35a3c915..14efce15 100644 --- a/impl-java/deps.edn +++ b/impl-java/deps.edn @@ -2,7 +2,7 @@ :aliases {:build ;; added by neil {:paths ["." "build" "src"] - :deps {io.github.clojure/tools.build {:git/tag "v0.8.1" :git/sha "7d40500"} + :deps {io.github.clojure/tools.build {:git/tag "v0.9.6" :git/sha "8e78bcc"} slipset/deps-deploy {:mvn/version "0.2.0"} org.babashka/sci.impl.types {:mvn/version "0.0.2"} ;; insn/insn {:mvn/version "0.5.3"} diff --git a/impl-java/src/babashka/impl/reify2/interfaces.clj b/impl-java/src/babashka/impl/reify2/interfaces.clj index da99f041..47e48377 100644 --- a/impl-java/src/babashka/impl/reify2/interfaces.clj +++ b/impl-java/src/babashka/impl/reify2/interfaces.clj @@ -1,6 +1,7 @@ (ns babashka.impl.reify2.interfaces) (def interfaces [java.nio.file.FileVisitor + java.nio.file.DirectoryStream$Filter java.io.FileFilter java.io.FilenameFilter clojure.lang.Associative diff --git a/project.clj b/project.clj index 4fecf855..2ae10385 100644 --- a/project.clj +++ b/project.clj @@ -29,7 +29,7 @@ [nrepl/bencode "1.2.0"] [borkdude/sci.impl.reflector "0.0.3"] [org.babashka/sci.impl.types "0.0.2"] - [org.babashka/babashka.impl.java "0.1.8"] + [org.babashka/babashka.impl.java "0.1.9"] [org.clojure/core.async "1.6.673"] [org.clojure/test.check "1.1.1"] [com.github.clj-easy/graal-build-time "0.1.0"] diff --git a/resources/META-INF/native-image/babashka/babashka/proxy-config.json b/resources/META-INF/native-image/babashka/babashka/proxy-config.json new file mode 100644 index 00000000..d204a8bb --- /dev/null +++ b/resources/META-INF/native-image/babashka/babashka/proxy-config.json @@ -0,0 +1,31 @@ +[{ + "interfaces": [ + "java.util.function.Predicate" + ] +}, + { + "interfaces": [ + "java.util.function.Function" + ] + }, + { + "interfaces": [ + "java.io.FileFilter" + ] + }, + { + "interfaces": [ + "java.nio.file.DirectoryStream$Filter" + ] + }, + { + "interfaces": [ + "java.util.function.Supplier" + ] + }, + { + "interfaces": [ + "java.util.function.UnaryOperator" + ] + } +] diff --git a/sci b/sci index 5d33aaa3..6c49b7ed 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 5d33aaa3f529d8a8da4837d5192cc244cdb9c9f3 +Subproject commit 6c49b7ed9346e05e0868193c355e7c38ca7bcec9 diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index a8821946..25d978a2 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -394,6 +394,7 @@ java.nio.file.FileVisitOption java.nio.file.FileVisitResult java.nio.file.Files + java.nio.file.DirectoryStream$Filter java.nio.file.LinkOption java.nio.file.NoSuchFileException java.nio.file.Path @@ -668,94 +669,101 @@ c)) m (assoc m :public-class (fn [v] + ;; (prn :v v) ;; NOTE: a series of instance check, so far, is still cheaper ;; than piggybacking on defmulti or defprotocol - (cond (instance? java.lang.Process v) - java.lang.Process - (instance? java.lang.ProcessHandle v) - java.lang.ProcessHandle - (instance? java.lang.ProcessHandle$Info v) - java.lang.ProcessHandle$Info - ;; added for calling .put on .environment from ProcessBuilder - (instance? java.util.Map v) - java.util.Map - ;; added for issue #239 regarding clj-http-lite - ;; can potentially be removed due to fix for #1061 - (instance? java.io.ByteArrayOutputStream v) - java.io.ByteArrayOutputStream - (instance? java.security.MessageDigest v) - java.security.MessageDigest - ;; streams - (instance? java.io.InputStream v) - java.io.InputStream - (instance? java.io.OutputStream v) - java.io.OutputStream - ;; java nio - (instance? java.nio.file.Path v) - java.nio.file.Path - (instance? java.nio.file.FileSystem v) - java.nio.file.FileSystem - (instance? java.nio.file.PathMatcher v) - java.nio.file.PathMatcher - (instance? java.util.stream.IntStream v) - java.util.stream.IntStream - (instance? java.util.stream.BaseStream v) - java.util.stream.BaseStream - (instance? java.nio.ByteBuffer v) - java.nio.ByteBuffer - (instance? java.nio.charset.Charset v) - java.nio.charset.Charset - (instance? java.nio.charset.CharsetEncoder v) - java.nio.charset.CharsetEncoder - (instance? java.nio.CharBuffer v) - java.nio.CharBuffer - (instance? java.nio.channels.FileChannel v) - java.nio.channels.FileChannel - (instance? java.nio.channels.ServerSocketChannel v) - java.nio.channels.ServerSocketChannel - (instance? java.nio.channels.SocketChannel v) - java.nio.channels.SocketChannel - (instance? java.net.CookieStore v) - java.net.CookieStore - ;; this makes interop on reified classes work - ;; see java_net_http_test/interop-test - (instance? sci.impl.types.IReified v) - (first (t/getInterfaces v)) - ;; fix for #1061 - (instance? java.net.URLClassLoader v) - java.net.URLClassLoader - (instance? java.lang.ClassLoader v) - java.lang.ClassLoader - (instance? java.nio.file.attribute.BasicFileAttributes v) - java.nio.file.attribute.BasicFileAttributes - (instance? java.util.concurrent.Future v) - java.util.concurrent.Future - (instance? java.util.concurrent.ScheduledExecutorService v) - java.util.concurrent.ScheduledExecutorService - (instance? java.util.concurrent.ExecutorService v) - java.util.concurrent.ExecutorService - (instance? java.util.Iterator v) - java.util.Iterator - (instance? javax.crypto.SecretKey v) - javax.crypto.SecretKey - (instance? javax.net.ssl.SSLSocketFactory v) - javax.net.ssl.SSLSocketFactory - (instance? javax.net.ssl.SSLSocket v) - javax.net.ssl.SSLSocket - (instance? java.lang.Thread v) - java.lang.Thread - (instance? java.util.concurrent.ThreadFactory v) - java.util.concurrent.ThreadFactory - (instance? java.security.cert.X509Certificate v) - java.security.cert.X509Certificate - (instance? java.io.Console v) - java.io.Console - (instance? java.util.Set v) - java.util.Set - (instance? java.io.Closeable v) - java.io.Closeable - ;; keep commas for merge friendliness - ))) + (let [res (cond (instance? java.lang.Process v) + java.lang.Process + (instance? java.lang.ProcessHandle v) + java.lang.ProcessHandle + (instance? java.lang.ProcessHandle$Info v) + java.lang.ProcessHandle$Info + ;; added for calling .put on .environment from ProcessBuilder + (instance? java.util.Map v) + java.util.Map + ;; added for issue #239 regarding clj-http-lite + ;; can potentially be removed due to fix for #1061 + (instance? java.io.ByteArrayOutputStream v) + java.io.ByteArrayOutputStream + (instance? java.security.MessageDigest v) + java.security.MessageDigest + ;; streams + (instance? java.io.InputStream v) + java.io.InputStream + (instance? java.io.OutputStream v) + java.io.OutputStream + ;; java nio + (instance? java.nio.file.Path v) + java.nio.file.Path + (instance? java.nio.file.FileSystem v) + java.nio.file.FileSystem + (instance? java.nio.file.PathMatcher v) + java.nio.file.PathMatcher + (instance? java.util.stream.Stream v) + java.util.stream.Stream + (instance? java.util.stream.IntStream v) + java.util.stream.IntStream + (instance? java.util.stream.BaseStream v) + java.util.stream.BaseStream + (instance? java.nio.ByteBuffer v) + java.nio.ByteBuffer + (instance? java.nio.charset.Charset v) + java.nio.charset.Charset + (instance? java.nio.charset.CharsetEncoder v) + java.nio.charset.CharsetEncoder + (instance? java.nio.CharBuffer v) + java.nio.CharBuffer + (instance? java.nio.channels.FileChannel v) + java.nio.channels.FileChannel + (instance? java.nio.channels.ServerSocketChannel v) + java.nio.channels.ServerSocketChannel + (instance? java.nio.channels.SocketChannel v) + java.nio.channels.SocketChannel + (instance? java.net.CookieStore v) + java.net.CookieStore + ;; this makes interop on reified classes work + ;; see java_net_http_test/interop-test + (instance? sci.impl.types.IReified v) + (first (t/getInterfaces v)) + ;; fix for #1061 + (instance? java.net.URLClassLoader v) + java.net.URLClassLoader + (instance? java.lang.ClassLoader v) + java.lang.ClassLoader + (instance? java.nio.file.attribute.BasicFileAttributes v) + java.nio.file.attribute.BasicFileAttributes + (instance? java.util.concurrent.Future v) + java.util.concurrent.Future + (instance? java.util.concurrent.ScheduledExecutorService v) + java.util.concurrent.ScheduledExecutorService + (instance? java.util.concurrent.ExecutorService v) + java.util.concurrent.ExecutorService + (instance? java.util.Iterator v) + java.util.Iterator + (instance? javax.crypto.SecretKey v) + javax.crypto.SecretKey + (instance? javax.net.ssl.SSLSocketFactory v) + javax.net.ssl.SSLSocketFactory + (instance? javax.net.ssl.SSLSocket v) + javax.net.ssl.SSLSocket + (instance? java.lang.Thread v) + java.lang.Thread + (instance? java.util.concurrent.ThreadFactory v) + java.util.concurrent.ThreadFactory + (instance? java.security.cert.X509Certificate v) + java.security.cert.X509Certificate + (instance? java.io.Console v) + java.io.Console + (instance? java.util.Set v) + java.util.Set + (instance? java.io.Closeable v) + java.io.Closeable + (instance? java.util.Collection v) + java.util.Collection + ;; keep commas for merge friendliness + )] + ;; (prn :res res) + res))) m (assoc m (list 'quote 'clojure.lang.Var) 'sci.lang.Var) m (assoc m (list 'quote 'clojure.lang.Namespace) 'sci.lang.Namespace)] m)) diff --git a/src/babashka/impl/reify.clj b/src/babashka/impl/reify.clj index 63dbf9e4..bb921190 100644 --- a/src/babashka/impl/reify.clj +++ b/src/babashka/impl/reify.clj @@ -187,5 +187,4 @@ sun.misc.SignalHandler {handle [[this signal]]} - })) diff --git a/test/babashka/interop_test.clj b/test/babashka/interop_test.clj index 096f0bca..645dac01 100644 --- a/test/babashka/interop_test.clj +++ b/test/babashka/interop_test.clj @@ -64,3 +64,14 @@ (deftest jio-line-number-reader-test (is (= 2 (bb nil "(def rdr (java.io.LineNumberReader. (java.io.StringReader. \"foo\nbar\"))) (binding [*in* rdr] (read-line) (read-line)) (.getLineNumber rdr)")))) + +(deftest FI-coercion + (is (true? (bb nil "(= [1 3] (into [] (doto (java.util.ArrayList. [1 2 3]) (.removeIf even?))))"))) + (is (true? (bb nil "(= \"abcabc\" (.computeIfAbsent (java.util.HashMap.) \"abc\" #(str % %)))"))) + (is (true? (bb nil "(= '(\\9) (-> \"a9-\" seq .stream (.filter Character/isDigit) stream-seq!))"))) + (is (true? (bb nil "(require (quote [clojure.java.io :as jio])) (import [java.io File] [java.nio.file Path Files DirectoryStream$Filter]) (pos? (count (seq (Files/newDirectoryStream (.toPath (jio/file \".\")) + #(-> ^Path % .toFile .isDirectory)))))"))) + (is (true? (bb nil "(import [java.util Collection] [java.util.stream Stream] [java.util.function Predicate]) + (= '(100 100 100 100 100) (->> (Stream/generate (constantly 100)) stream-seq! (take 5)))"))) + (is (true? (bb nil "(import [java.util Collection] [java.util.stream Stream] [java.util.function Predicate]) + (= '(1 2 3 4 5 6 7 8 9 10) (->> (Stream/iterate 1 inc) stream-seq! (take 10)))")))) diff --git a/test/babashka/reify_test.clj b/test/babashka/reify_test.clj index a9911dd7..b2903d70 100644 --- a/test/babashka/reify_test.clj +++ b/test/babashka/reify_test.clj @@ -153,3 +153,10 @@ (force-gc) @deleted? "))) + +(deftest reify-dir-stream-filter + (is (true? (bb nil " +(defn get-dir-stream [^java.nio.file.Path dir-path glob-pattern] + (let [path (.toPath (java.io.File. dir-path))] + (java.nio.file.Files/newDirectoryStream path glob-pattern))) +(pos? (count (seq (get-dir-stream \".\" (reify java.nio.file.DirectoryStream$Filter (accept [_ path] (.isDirectory (.toFile path))))))))"))))