diff --git a/CHANGELOG.md b/CHANGELOG.md index 53aef05a..a1c75415 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ A preview of the next release can be installed from Check out our new project: [bbin](https://github.com/babashka/bbin): install any Babashka script or project with one command. +- Throw exception on attempt to reify multiple interfaces +- Allow java.lang.Object reify with empty methods + +## 0.9.162 (2022-09-04) + +Check out our new project: [bbin](https://github.com/babashka/bbin): install any Babashka script or project with one command. + - [#1343](https://github.com/babashka/babashka/issues/1343): Fix postgres feature - [#1345](https://github.com/babashka/babashka/issues/1345): add `javax.net.ssl.SSLException` and `java.net.SocketTimeoutException` classes ([@lread](https://github.com/lread)) - Fix `satisfies?` with marker protocol (no methods) diff --git a/deps.edn b/deps.edn index 535ddb10..0576a7a5 100644 --- a/deps.edn +++ b/deps.edn @@ -16,7 +16,8 @@ "babashka.nrepl/src" "depstar/src" "process/src" "deps.clj/src" "deps.clj/resources" - "resources" "sci/resources"], + "resources" "sci/resources" + "reify/src"], :deps {org.clojure/clojure {:mvn/version "1.11.1"}, org.babashka/sci {:local/root "sci"} org.babashka/babashka.impl.reify {:mvn/version "0.1.2"} diff --git a/reify/src/babashka/impl/reify2.clj b/reify/src/babashka/impl/reify2.clj index ec2636c2..dff57479 100644 --- a/reify/src/babashka/impl/reify2.clj +++ b/reify/src/babashka/impl/reify2.clj @@ -45,8 +45,26 @@ (invoke [this a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20] (invoke-fn this a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20)) (applyTo [this arglist] (apply-fn this arglist))))) +(defn reify-object [m] + (let [methods (:methods m) + toString-fn (or (get methods 'toString) + (fn [this] + (str + (.getName (.getClass this)) + "@" + (Integer/toHexString (.hashCode this)))))] + (reify + sci.impl.types.IReified + (getMethods [_] (:methods m)) + (getInterfaces [_] (:interfaces m)) + (getProtocols [_] (:protocols m)) + java.lang.Object + (toString [this] (toString-fn this))))) + (defmacro gen-reify-fn [] `(fn [~'m] + (when (> (count (:interfaces ~'m)) 1) + (throw (UnsupportedOperationException. "babashka reify only supports implementing a single interface"))) (if (empty? (:interfaces ~'m)) (reify sci.impl.types.IReified @@ -55,19 +73,12 @@ (getProtocols [_] (:protocols ~'m))) (case (.getName ~(with-meta `(first (:interfaces ~'m)) {:tag 'Class})) - "java.lang.Object" - (reify - java.lang.Object - (toString [~'this] - ((method-or-bust (:methods ~'m) (quote ~'toString)) ~'this)) - sci.impl.types.IReified - (getMethods [_] (:methods ~'m)) - (getInterfaces [_] (:interfaces ~'m)) - (getProtocols [_] (:protocols ~'m))) ~@(mapcat identity (cons ["clojure.lang.IFn" - `(reify-ifn ~'m)] + `(reify-ifn ~'m) + "java.lang.Object" + `(reify-object ~'m)] (for [i interfaces] (let [in (.getName ^Class i)] [in diff --git a/test/babashka/reify_test.clj b/test/babashka/reify_test.clj index be7b553b..7e052b5e 100644 --- a/test/babashka/reify_test.clj +++ b/test/babashka/reify_test.clj @@ -51,6 +51,11 @@ ]"))))) (deftest reify-object + (testing "empty methods" + (is (clojure.string/starts-with? + (bb nil " +(str (reify Object))") + "babashka.impl.reify"))) (testing "toString" (is (= ":foo" (bb nil " @@ -114,3 +119,12 @@ iter (reify java.util.function.Consumer (accept [_ x] (vswap! res conj x)))) (= [true :a :b :c] @res))] (is (true? (bb nil prog))))) + +(deftest reify-multiple-interfaces-test + (testing "throws exception" + (is (thrown? + clojure.lang.ExceptionInfo + (bb nil " +(reify + java.lang.Object (toString [_] \"foo\") + clojure.lang.Seqable (seq [_] '(1 2 3)))")))))