In the Argonaut DecodeJson
trait there is a method |||
for chaining together decoders, so that the first succeeding decoder is chosen. There is also a similar method in DecodeResult
which has the same effect. It looks at first glance as though one of these would be what we want for decoding multiple subtypes of a common trait. However, how do we actually do this?
The first problem is that the argument to |||
has to be a DecodeJson
decoding a supertype of the type that the callee is supposed to be decoding (and similarly for DecodeResult
). I would expect that such a decoder would be able to decode all of the subtypes of the common supertype, so this seems like a recipe for infinite recursion!
We can get around this using the following ugly asInstanceOf
hack while defining the CodecJson
for the supertype:
c => c.as[A] ||| c.as[Foo](implicitly[DecodeJson[B]].asInstanceOf[DecodeResult[Foo]])
However, then there is still a problem when decoding more than two subtypes. Assume there are subtypes A
, B
and C
of Foo
. Now what? How do we add yet another alternative to this decoding expression? .asInstanceOf[DecodeResult[AnyRef]]
is going to destroy the type-safety of the parsed result (as if we hadn't already discarded type-safety at this point!). And then we are quickly going to run out of options with 4, 5, or 6 alternatives.
EDIT: I will gladly accept as an answer any alternative approach to decoding more-than-2-wide subtype hierarchies using Argonaut.