diff --git a/CHANGELOG.md b/CHANGELOG.md index a1c75415..4aa0e1ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ For a list of breaking changes, check [here](#breaking-changes). A preview of the next release can be installed from [babashka-dev-builds](https://github.com/babashka/babashka-dev-builds). +## Unreleased + +- [#1358](https://github.com/babashka/babashka/issues/1358): Expose a subset of java.lang.ref to enable hooking into the destruction/GC of objects + ## 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. diff --git a/reify/src/babashka/impl/reify2.clj b/reify/src/babashka/impl/reify2.clj index dff57479..3186ceaf 100644 --- a/reify/src/babashka/impl/reify2.clj +++ b/reify/src/babashka/impl/reify2.clj @@ -61,6 +61,19 @@ java.lang.Object (toString [this] (toString-fn this))))) +(defn reify-runnable [m] + (let [methods (:methods m) + run-fn (or (get methods 'run) + (fn [_]))] + (reify + sci.impl.types.IReified + (getMethods [_] (:methods m)) + (getInterfaces [_] (:interfaces m)) + (getProtocols [_] (:protocols m)) + java.lang.Runnable + (run [this] (run-fn this)))) + ) + (defmacro gen-reify-fn [] `(fn [~'m] (when (> (count (:interfaces ~'m)) 1) @@ -78,7 +91,9 @@ ["clojure.lang.IFn" `(reify-ifn ~'m) "java.lang.Object" - `(reify-object ~'m)] + `(reify-object ~'m) + "java.lang.Runnable" + `(reify-runnable ~'m)] (for [i interfaces] (let [in (.getName ^Class i)] [in diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 306d7e75..cbe81f35 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -84,6 +84,8 @@ java.lang.reflect.Array {:methods [{:name "newInstance"} {:name "set"}]} + java.lang.Runnable + {:methods [{:name "run"}]} java.net.Inet4Address {:methods [{:name "getHostAddress"}]} java.net.Inet6Address @@ -264,6 +266,9 @@ java.lang.System java.lang.Throwable ;; java.lang.UnsupportedOperationException + java.lang.ref.WeakReference + java.lang.ref.ReferenceQueue + java.lang.ref.Cleaner java.math.BigDecimal java.math.BigInteger java.math.MathContext diff --git a/test/babashka/reify_test.clj b/test/babashka/reify_test.clj index 7e052b5e..82c4a08a 100644 --- a/test/babashka/reify_test.clj +++ b/test/babashka/reify_test.clj @@ -128,3 +128,26 @@ (reify java.lang.Object (toString [_] \"foo\") clojure.lang.Seqable (seq [_] '(1 2 3)))"))))) + +(deftest reify-runnable-and-garbage-collection-test + (is (bb nil " +(def cleaner (java.lang.ref.Cleaner/create)) +(def deleted? (atom false)) +(defn make-cleanable-ref [] + (let [obj (Object.)] + (.register cleaner obj + (reify java.lang.Runnable + (run [_] + (reset! deleted? true)))) + nil)) +(defn force-gc [] + (let [t (atom (Object.)) + wr (java.lang.ref.WeakReference. @t)] + (reset! t nil) + (while (.get wr) + (System/gc) + (System/runFinalization)))) +(make-cleanable-ref) +(force-gc) +@deleted? +")))