jsonscalaserializationjsoniter-scala

How to customize serialization of a key of a Map with jsoniter


I have a claas that jsoniter is able to create automatically a custom codec, except for the key of a map.

How to create a custom codec just for the key?

case class IconReference(area: AreaId, source: IconSource, id: String)

sealed trait TreeStatisticOperation:
    id: String

case class ApiTreeNode(
    value: String,
    label: String,
    field: String,
    path: List[Int],
    icon: Option[IconReference],
    statistics: Map[TreeStatisticOperation, Option[Double]],
  )

In this example, I need only to customize how TreeStatisticOperation is handled, and avoid writing a codec that handles all the details.


Solution

  • You need to define an implicit JsonKeyCodec:

    given JsonKeyCodec[String] with {
      def decodeKey(in: JsonReader): String           = in.readKeyAsString()
      def encodeKey(x: String, out: JsonWriter): Unit = out.writeKey(x)
    }
    

    Unfortunately, there is no macro for it, nor any .map/.contramap, so you'd have to use methods in JsonReader and JsonWriter to get one of primitives (String, Boolean, numeric type) and convert to/from it manually.

    In your case that would be:

    given JsonKeyCodec[TreeStatisticOperation] with {
      def decodeKey(in: JsonReader): TreeStatisticOperation =
        // assuming withName(name: String): TreeStatisticOperation
        TreeStatisticOperation.withName(in.readKeyAsString())
      def encodeKey(x: TreeStatisticOperation, out: JsonWriter): Unit =
        out.writeKey(x.id)
    }