Closed greglook closed 4 years ago
I'm running into this scenario, and think this feature would be great. Another place I've seen something similar is in transit
. If I have time I will look further into how something like this would fit into clj-cbor
and put together a PR.
In any case, thanks for the work you've put into this lib, it's a breeze to work with.
Thanks! Always great to hear positive feedback.
I looked into this a bit more, and there are ways to add this functionality with the existing code. In write-handled
, the codec uses the :dispatch
function to generate a lookup value, then calls :write-handlers
as a function on that lookup to find if there is a custom handler:
That means that a caller could either use a custom dispatch function which maps known problem classes to the desired lookup value, or they could replace the default hash-map for write-handlers with something that does more sophisticated lookup behavior.
That looks great—it's cool that the library supports this without further modification.
Just to make sure I'm interpreting this correctly, are you thinking that the custom dispatch function would be convenient for manually specifying how a class should be mapped to a handler, while replacing write-handlers
with something more sophisticated would capture more generic changes to the lookup algorithm?
I think I'm getting it, and if so, that solves the whole problem really cleanly. Thanks for pointing this out, this was mega helpful.
Yeah - the dispatch function would let you alias specific types if you wanted to. To use the DateTimeZone
example, you could do this to address it:
(defn encoder-class
[x]
(if (instance? DateTimeZone x)
DateTimeZone
(class x)))
(def codec
(cbor/cbor-codec :dispatch encoder-class))
You could also address it more generally by replacing the write handlers, similar to how Puget does it.
Added a utility function for this and released it in 1.0.0
.
There are a few real-world use-cases that have cropped up where the majority of a type's API uses an abstract parent class or interface, with multiple underlying concrete implementations. One example is Joda's
org.joda.time.DateTimeZone
and the attendantCachedDateTimeZone
,FixedDateTimeZone
, andDateTimeZoneBuilder$PrecalculatedZone
(yuck). The user wants to be able to treat all of these types uniformly, so having to declare every possible subclass makes type extension awkward here.This can be solved by attempting inheritance-based resolution, similar to
puget.dispatch/inheritance-lookup
.