Skip to content

Round-trip fails when write handler returns extension type #23

@ghost

Description

It appears that when a write handler returns an object which is not a Transit ground type, the corresponding read handler gets called with a decoder.Tag value instead of the fully-decoded value.

This only applies in :json mode, not :json-verbose.

Sample ClojureScript code:

(ns example
  (:require [cognitect.transit :as transit]))

(defrecord VectorBox [value])

(defrecord ListBox [value])

;; This Transit write handler returns a Vector, which is a Transit
;; ground type.
(deftype VectorBoxWriteHandler []
  Object
  (tag [_ box] "vectorbox")
  (rep [_ box] (vec (:value box)))
  (stringRep [_ box] nil))

;; This Transit write handler returns a List, which is an extension
;; type in Transit, not a ground type.
(deftype ListBoxWriteHandler []
  Object
  (tag [_ box] "listbox")
  (rep [_ box] (list* (:value box)))
  (stringRep [_ box] nil))

(def my-write-handlers
  {VectorBox (VectorBoxWriteHandler.)
   ListBox (ListBoxWriteHandler.)})

(def my-read-handlers
  {"vectorbox" (fn [rep] (->VectorBox (vec rep)))
   "listbox" (fn [rep] (->ListBox (vec rep)))})

(defn round-trip
  "Returns the result of writing value with Transit and then reading
  it back. transit-type is either :json or :json-verbose"
  [value transit-type]
  {:pre [(contains? #{:json :json-verbose} transit-type)]}
  (transit/read
   (transit/reader transit-type {:handlers my-read-handlers})
   (transit/write
    (transit/writer transit-type {:handlers my-write-handlers})
    value)))

(def test-value {:listbox (->ListBox [1 2 3])
                 :vectorbox (->VectorBox [1 2 3])})

(defn test-round-trip-verbose
  "Asserts that we can successfully round-trip a value through transit
  using :json-verbose encoding."
  []
  (assert (= test-value (round-trip test-value :json-verbose))))

(defn test-round-trip-json
  "Asserts that we can successfully round-trip a value through transit
  using :json encoding. This test fails."
  []
  (assert (= test-value (round-trip test-value :json))))

Tested with these dependencies:

 [com.cognitect/transit-cljs "0.8.232"]
   [com.cognitect/transit-js "0.8.755"]
 [org.clojure/clojure "1.7.0"]
 [org.clojure/clojurescript "1.7.170"]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions