Welcome! Please see the About page for a little more info on how this works.

+1 vote
in data.json by

Problem

When writing json, I'd like to set a fallback function on a per write call basis to be called with the value when no other JSONWriter implementation can handle the type (for example, call my function here instead of throwing).

An example use case where setting a fallback function on a per write basis would be useful is logging. When logging JSON, most often you want to do your very best effort to avoid the log execution and serialization from throwing. If you throw, you lose information, and obscure the actual error. For this reason, when logging JSON, and you encounter an object without a JSONWriter implementation, it is helpful to simply call str on it, rather than failing with an exception. An important part of this use case is that you do not know the type of objects that might be passed in upfront.

Proposed solution

Add an option :default-fn to write to handle the default case. This function would be called with 3 parameters x, out, and options and would be expected to print x to out however desired. The :default-fn function would get called in write-generic for the case when x is not an array (see code here). The default setting for :default-fn would get added to default-write-options here. The default setting would behave exactly as the current implementation does -- throwing an exception.

(defn default-default-fn
  [x out options]
  (throw (Exception. (str "Don't know how to write JSON of " (class x)))))

This solution is minimally invasive, and is an additive change. It allows the user to pass a fallback function to write unhanded objects without workaround like mutating global state.

Other potential solutions

  1. data.json does not permit the user to control how any of the default objects are encoded. A much more invasive, and larger change would be to allow the user to customize how any or all of the defaults get written. A change of this magnitude would require much more research into how it could be done efficiently, how others are doing it, etc.

Current Workaround

The only option at present is to globally override the Object extension of JSONWriter to call my own function instead of the built-in one. This has the downside that it is a global override -- not all jvm users of data.json may want do-my-special-thing to be the default.

(defn my-custom-json-write-generic [x out options]
  (if (.isArray (class x))
    (json/-write (seq x) out options)
    (do-my-special-thing x out options)))

(extend java.lang.Object json/JSONWriter {:-write my-custom-json-write-generic})

1 Answer

0 votes
by
...