Hotfix: fn?s were incorrectly reporting true for serializable?

This commit is contained in:
Peter Taoussanis 2016-06-17 12:03:07 +07:00
parent 1670535332
commit 537b39aba2
2 changed files with 42 additions and 31 deletions

View file

@ -659,13 +659,17 @@
(defn try-write-serializable [out x] (defn try-write-serializable [out x]
(when (utils/serializable? x) (when (utils/serializable? x)
(try (write-serializable out x) true (try
(catch Throwable _ nil)))) (write-serializable out x)
true
(catch Throwable _ nil))))
(defn try-write-readable [out x] (defn try-write-readable [out x]
(when (utils/readable? x) (when (utils/readable? x)
(try (write-readable out x) true (try
(catch Throwable _ nil)))) (write-readable out x)
true
(catch Throwable _ nil))))
(defn- try-pr-edn [x] (defn- try-pr-edn [x]
(try (try

View file

@ -5,40 +5,50 @@
ObjectOutputStream ObjectInputStream])) ObjectOutputStream ObjectInputStream]))
;;;; Fallback type tests ;;;; Fallback type tests
;; Unfortunately the only reliable way we can tell if something's ;; Unfortunately the only ~reliable way we can tell if something's
;; really serializable/readable is to actually try a full roundtrip. ;; really serializable/readable is to actually try a full roundtrip.
(defn- memoize-type-test [f-test] (defn- memoize-type-test [test-fn]
(let [cache (atom {})] ; {<type> <type-okay?>} (let [cache (atom {})] ; {<type> <type-okay?>}
(fn [x] (fn [x]
(let [t (type x) (let [t (type x)
;; This is a bit hackish, but no other obvious solutions (?): ;; This is a bit hackish, but no other obvious solutions (?):
cacheable? (not (re-find #"__\d+" (str t))) ; gensym form cacheable? (not (re-find #"__\d+" (str t))) ; gensym form
test (fn [] (try (f-test x) (catch Exception _ false)))] test (fn [] (try (test-fn x) (catch Exception _ false)))]
(if-not cacheable? (test) (if cacheable?
@(enc/swap-val! cache t #(if % % (delay (test))))))))) @(enc/swap-val! cache t #(if % % (delay (test))))
(test))))))
(def readable? (memoize-type-test (fn [x] (-> x enc/pr-edn enc/read-edn) true)))
(def serializable? (def serializable?
(memoize-type-test (let [test-fn
(fn [x] (fn [x]
(when (instance? Serializable x) (let [class-name (.getName (class x))
(let [class-name (.getName (class x)) class ^Class (Class/forName class-name) ; Try 1st (fail fast)
class ^Class (Class/forName class-name) ; Try 1st (fail fast) bas (ByteArrayOutputStream.)
bas (ByteArrayOutputStream.) _ (.writeObject (ObjectOutputStream. bas) x)
_ (.writeObject (ObjectOutputStream. bas) x) ba (.toByteArray bas)
ba (.toByteArray bas) object (.readObject (ObjectInputStream.
object (.readObject (ObjectInputStream. (ByteArrayInputStream. ba)))]
(ByteArrayInputStream. ba)))] (cast class object)
(cast class object) true))
true)))))
(def readable? (memoize-type-test (fn [x] (-> x enc/pr-edn enc/read-edn) true))) mtt (memoize-type-test test-fn)]
(fn [x]
(if (instance? Serializable x)
(if (fn? x)
false ; Reports as true but is unreliable
(mtt x))
false))))
(comment (comment
(enc/qb 1000 (serializable? "Hello world")) ; Cacheable (enc/qb 10000
(enc/qb 1000 (serializable? (fn []))) ; Uncacheable (readable? "Hello world") ; Cacheable
(enc/qb 1000 (readable? "Hello world")) ; Cacheable (serializable? "Hello world") ; Cacheable
(enc/qb 1000 (readable? (fn [])))) ; Uncacheable (readable? (fn [])) ; Uncacheable
(serializable? (fn [])) ; Uncacheable
))
;;;; ;;;;
@ -110,11 +120,8 @@
(is? x java.util.UUID) (is? x java.util.UUID)
(is? x java.util.regex.Pattern) (is? x java.util.regex.Pattern)
(when (and allow-clojure-reader? (readable? x)) :clojure-reader) (when (and allow-clojure-reader? (readable? x)) :clojure-reader)
(when (and allow-java-serializable? (when (and allow-java-serializable? (serializable? x)) :java-serializable)))))
;; Reports as true but is unreliable:
(not (is? x clojure.lang.Fn))
(serializable? x)) :java-serializable)))))
(comment (comment
(enc/qb 10000 (freezable? "hello")) ; 0.79 (enc/qb 10000 (freezable? "hello")) ; 0.79