1

I'm using Scala's uPickle to parse this JSON:

{ "somevalue": 1, "revenue": [], "boost": { ... } }

The problem is that "revenue" is sometimes an object, and sometimes it's an empty array. If it's an empty array, this means that the value is not there (it should be null or absent, but I'm not generating this json, so I have to adapt).

Is it possible to convince uPickle so that when it expects a Map[_,_] and gets an empty sequence, to emit an empty object? I would imagine declaring a case class for the json above like this:

case class MyObject {
    val somevalue: Int,
    val revenue: Map[String, RevenueChildItem],
    val boost: Map[String, BoostChildItem],
}

Currently uPickle will abort with error "expecting object, got sequence".

I can maybe pre-process the JSON file before parsing, but first I would like to know if uPickle is able to do something like this?

I know I probably can do it with a custom pickler, but I have a few dozen of structs to parse, each of those structs has the same rules (i.e. empty sequence in case of an empty object) and it would be really good to do it in a more general way, and apply it everywhere automatically.

antonone
  • 2,045
  • 1
  • 25
  • 35

1 Answers1

0

It seems that this will work:

implicit def emptyArrToEmptyDict[T: Reader]: Reader[Map[String, T]] = {
  reader[ujson.Value].map[Map[String, T]] {
    case ujson.Arr(array) if array.length == 0 => Map()
    case other => other.obj.map { case (k, v) => (k -> v.transform(implicitly[Reader[T]])) }.toMap
  }
}

uPickle should pick it up automatically if you put it in some object and you import the emptyArrToEmptyDict name to the global namespace.

antonone
  • 2,045
  • 1
  • 25
  • 35