How to define a flexible String decoder with ZIO JSON

January 20, 2023

I am using ZIO JSON to decode responses from a Web service and I’ve faced an issue : some objects have fields that can sometimes be strings and sometime be integers.

This can be solved with decoders orElse method like this :

case class SoftwareVersion(
                            name: String,
                            // ...
                          )

case class SoftwareVersionWithIntName(
                            name: Int,
                            // ...
                          )

object Decoders{
  implicit val softwareVersionDecoder = DeriveJsonDecoder.gen[SoftwareVersion].orElse(
    DeriveJsonDecoder.gen[SoftwareVersionWithIntName].map(decoded =>
      SoftwareVersion(decoded.name.toString)
    )
  )
}

It is working but if there is a lot of changing fields, it may lead to a lot of cases to manage.

To make it work at any level with the minimum amount of code, you can hack the String decoder itself :

implicit val flexStringDecoder = JsonDecoder[String].orElse(
  JsonDecoder[Int].map(decoded => decoded.toString)
)

Use it with caution!

The same trick should also work with Circe.

comments powered by Disqus