0
votes

I have a scala service that calls to TensorFlow service by HTTP. I'm trying to encode None value to NaN as JSON with circe (how TensorFlow expect it), but and I'm getting "null" after encoding the object

Suppose I have the following case class that need to be serialized as JSON objects using circe:

case class MyRequest(instance: Option[Double])

object MyRequest extends CirceDefaults {
  implicit val autoEncoderRequestEncoder: Encoder[MyRequest] = { (myRequest: MyRequest) =>
    myRequest.instance match {
      case Some(value) => Json.fromDouble(value).asJson
      case None => None.asJson
    }
  }
}

So None.asJson encoded to "null" and not NaN and im getting error from tensorflow service:

Error: Invalid argument: JSON Value: "null" Type: String is not of expected type: float"

Any help would be greatly appreciated.

1

1 Answers

3
votes

This is default Circe behavior. Please, see for more details: https://github.com/circe/circe/issues/1267

And seems like not only for Circe, but in general JSON standard has no such thing as Nan, -Infinity, +Infinity, so in Circe, you can't even create Json for Double.Nan: https://github.com/circe/circe/blob/master/modules/core/shared/src/main/scala/io/circe/Json.scala#L517

So Json.fromDouble(Double.Nan) returns None - because Double.Nan is not real: https://github.com/circe/circe/blob/master/modules/core/shared/src/main/scala/io/circe/Json.scala#L575

Hence, in order to render Nan the way you want to, unfortunately, you will need to edit JSON string after rendering

import io.circe._, io.circe.generic.semiauto._, io.circe.syntax._

case class MyRequest(instance: Option[Double])

object MyRequest {
  implicit val encoder: Encoder[MyRequest] = request => {
    request.instance.fold(Json.fromString("NaN"))(_.asJson)
  }
}

case class BigRequest(request: MyRequest)

object BigRequest {
  implicit val encoder: Encoder[BigRequest] = deriveEncoder[BigRequest]
}

println(BigRequest(MyRequest(Some(1.0d))).asJson.noSpaces)

println(BigRequest(MyRequest(None)).asJson.noSpaces.replace(""""NaN"""", "NaN"))

Scatie: https://scastie.scala-lang.org/SGHtB9GZRpShtQ6A8qAZsA