-
Notifications
You must be signed in to change notification settings - Fork 14
Creating custom handlers
Alex Miller edited this page May 6, 2014
·
5 revisions
Fressian provides handlers for the following tags and their Java representation:
- short, integer, long - java.lang.[Short,Integer,Long]
- double, float - java.lang.[Double,Float]
- boolean - java.lang.Boolean
- byte[], int[], long[], float[], boolean[], double[], Object[]
- string - java.lang.String
- null
- any - TaggedObject
- list - java.util.List
- map - java.util.HashMap
- set - java.util.HashSet
- uuid - java.util.uuid
- regex - java.util.regex.Pattern
- uri - java.net.URI
- bigint - java.math.BigInteger
- bigdec - java.math.BigDecimal
- inst - java.util.Date
data.fressian adds an additional set of handlers that cover many common Clojure types:
- char - java.lang.Character
- ratio - clojure.lang.Ratio
- record - Clojure records
- symbol - clojure.lang.Symbol
- key - clojure.lang.Keyword
- bigint - clojure.lang.BigInt
To add your own tag or override existing tags, you must implement ReadHandler and WriteHandler and merge those mappings into the data.fressian mappings (which are used by default).
Let's add support for the java.awt.Point class. First define the read handler and write handler for Point:
;;;; Example ns header setting up imports and requires
(ns mytest
(:require [clojure.data.fressian :as fressian])
(:import [java.awt Point]
[java.io ByteArrayOutputStream ByteArrayInputStream]
[org.fressian.handlers WriteHandler ReadHandler]))
;; This is the bytecode "tag" for our new type
(def point-tag "point")
;; This WriteHandler will be invoked for an instance of Point
(def point-writer
(reify WriteHandler
(write [_ writer point] ;; see org.fressian.Writer
(.writeTag writer point-tag 2) ;; write tag and expect 2 components
(.writeInt writer (.x point)) ;; 1st component
(.writeInt writer (.y point))))) ;; 2nd component
;; This ReadHandler will be invoked when a "point" tag is read
(def point-reader
(reify ReadHandler
(read [_ reader tag component-count] ;; see org.fressian.Reader
(Point. (.readInt reader) (.readInt reader)))))
;; Merge our handler (class -> tag -> writer) into standard clojure.write-handlers
;; Then wrap with associative-lookup, and inheritance-lookup
(def my-write-handlers
(-> (merge {java.awt.Point {point-tag point-writer}}
fressian/clojure-write-handlers)
fressian/associative-lookup
fressian/inheritance-lookup))
;; Merge our handler (tag -> reader) into standard clojure-read-handlers
;; Then wrap with associative-lookup
(def my-read-handlers
(-> (merge {point-tag point-reader} fressian/clojure-read-handlers)
fressian/associative-lookup))
;; Demo roundtrip of Point
(defn demo []
(let [baos (ByteArrayOutputStream.)
;; create writer with my-write-handlers
writer (fressian/create-writer baos :handlers my-write-handlers)
point (Point. 1 2)]
(fressian/write-object writer point)
(let [bais (ByteArrayInputStream. (.toByteArray baos))
;; create reader with my-read-handlers
reader (fressian/create-reader bais :handlers my-read-handlers)
out (fressian/read-object reader)]
(assert (= point out))))) ;; yup, got the same Point data!