Argonaut CodecJson and decoding subtypes
Asked Answered
G

0

6

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.

Gramnegative answered 25/8, 2015 at 19:1 Comment(3)
It's much more common to use a discriminator to tag subtypes (especially in the case of ADTs)—otherwise you run into problems like the ones you mention, as well as the fact that some perfectly reasonable subtypes may have the same JSON representation and not be distinguishable by the approach you describe.Pantile
It's also worth noting that both circe and argonaut-shapeless provide generic codec derivation mechanisms for sealed trait hierarchies that use discriminators.Pantile
@TravisBrown: Any chance you could provide an example of these tags as an answer?Secondary

© 2022 - 2024 — McMap. All rights reserved.