BSON to Play JSON support for Long values

179 Views Asked by At

I've started using the play-json/play-json-compat libraries with reactivemongo 0.20.11.

So I can use JSON Play reads/writes while importing the 'reactivemongo.play.json._' package and then easily fetch data from a JSONCollection instead of a BSONCollection. For most cases, this works great but for Long fields, it doesn't :(

For example:

case class TestClass(name: String, age: Long)

object TestClass {
  implicit val reads = Json.reads[TestClass]
}

If I try querying using the following func:

def getData: Map[String, TestClass] = {
  val res = collection.find(emptyDoc)
    .cursor[TestClass]()
    .collect[List](-1, Cursor.ContOnError[List[TestClass]] { case (_, t) =>
      failureLogger.error(s"Failed deserializing TestClass from Mongo", t)
    })
    .map { items =>
      items map { item =>
        item.name -> item.age
      } toMap
    }
  Await.result(res, 10 seconds)
}

Then I get the following error:

play.api.libs.json.JsResultException: JsResultException(errors:List((/age,List(ValidationError(List(error.expected.jsnumber),WrappedArray())))))

I've debugged the reading of the document and noticed that when it first converts the BSON to a JsObject, then the long field is as following:

"age": {"$long": 1526389200000}

I found a way to make this work but I really don't like it:

case class MyBSONLong(`$long`: Long)

object MyBSONLong {
  implicit val longReads = Json.reads[MyBSONLong]
}

case class TestClass(name: String, age: Long)

object TestClass {
  implicit val reads = (
    (__ \ "name").read[String] and
      (__ \ "age").read[MyBSONLong].map(_.`$long`)
    ) (apply _)
}

So this works, but it's a very ugly solution. Is there a better way to do this?

Thanks in advance :)

0

There are 0 best solutions below