cognitect / transit-cljs

Transit for ClojureScript
http://transit-format.org
Apache License 2.0
323 stars 20 forks source link

With :json, caching strips some values due to serialization counting errors #22

Closed mrcslws closed 8 years ago

mrcslws commented 8 years ago

This took a while to track down. I reduced it down to this minimal input:

(def pathological
  [{:any-value {["this vector makes this a cmap"] "any value"
                "any string" :victim}}
   {:victim :any-other-value}])

transit-cljs fails to serialize that properly. I've verified this by roundtripping it, and testing in Clojure. You can see below that it strips the second :victim.

ClojureScript: Fails

(defn clojurescript-test [v]
  (let [_ (println "ORIGINAL VALUE:")
        _ (println v)
        serialized (transit/write (transit/writer :json) v)
        _ (println "SERIALIZED:")
        _ (println serialized)
        roundtrip (transit/read (transit/reader :json) serialized)]
    (if (= v roundtrip)
      (println "Successful roundtrip")
      (do
        (println "FAILURE")
        (println "ROUNDTRIP VALUE:")
        (println roundtrip)))))

(clojurescript-test pathological)

OUTPUT:

ORIGINAL VALUE:
[{:any-value {[this vector makes this a cmap] any value, any string :victim}} {:victim :any-other-value}]
SERIALIZED:
[["^ ","~:any-value",["~#cmap",[["this vector makes this a cmap"],"any value","any string","~:victim"]]],["^ ","^3","~:any-other-value"]]
FAILURE
ROUNDTRIP VALUE:
[{:any-value {[this vector makes this a cmap] any value, any string :victim}} {nil :any-other-value}]

Clojure: Succeeds

(defn clojure-test [v]
  (let [_ (println "ORIGINAL VALUE:")
        _ (println v)
        serialized (let [out (ByteArrayOutputStream.)]
                     (transit/write (transit/writer out :json) v)
                     (.toString out))
        _ (println "SERIALIZED:")
        _ (println serialized)
        roundtrip (let [in (-> serialized
                               (.getBytes "UTF-8")
                               ByteArrayInputStream.)]
                    (transit/read (transit/reader in :json)))]
    (if (= v roundtrip)
      (println "Successful roundtrip")
      (do
        (println "FAILURE")
        (println "ROUNDTRIP VALUE:")
        (println roundtrip)))))

(clojure-test pathological)

OUTPUT:

ORIGINAL VALUE:
[{:any-value {[this vector makes this a cmap] any value, any string :victim}} {:victim :any-other-value}]
SERIALIZED:
[["^ ","~:any-value",["~#cmap",[["this vector makes this a cmap"],"any value","any string","~:victim"]]],["^ ","^2","~:any-other-value"]]
Successful roundtrip
mrcslws commented 8 years ago

When I say "counting errors", I'm pointing out the "^3" and the "^2" in ClojureScript / Clojure, respectively.

swannodette commented 8 years ago

Thanks for the report will take a look.

swannodette commented 8 years ago

fixed https://github.com/cognitect/transit-cljs/commit/0ab1920a10b736e4484993c2b0ff131501442aa5