Scala Json Deserialize with null or Option[Int]

1k Views Asked by At

I have the following case class defined in Scala

case class BitmexTradeData(
      foreignNotional: Option[Int],
      grossValue: Option[Int],
      homeNotional: Option[Double],
      price: Double,
      side: Side,
      size: Double,
      symbol: String,
      tickDirection: String,
      timestamp: Instant,
      trdMatchID: String
)

Now when I get the following json string which i wanted to deserialize back to BitmexTradeData:

{
  "timestamp": "2019-10-17T01:34:00.000Z",
  "symbol": ".BTRXXBT",
  "side": "Buy",
  "size": 0,
  "price": 0.00000187,
  "tickDirection": "PlusTick",
  "trdMatchID": "00000000-0000-0000-0000-000000000000",
  "grossValue": null,
  "homeNotional": null,
  "foreignNotional": null
}

I get the following error:

spray.json.DeserializationException: Expected Int as JsNumber, but got null

the way I am deserializing it is following:

msg.parseJson.convertTo[BitmexTradeData]

The ouput that I am expecting is BitmexTradeData Object with foreignNotional as optional.empty as some times these value are null.

1

There are 1 best solutions below

0
Andriy Plokhotnyuk On

If you are not locked to use spray-json only then add jsoniter-scala to your dependency list:

libraryDependencies ++= Seq(
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core"   % "1.0.0" % Compile,
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "1.0.0" % Provided // required only in compile-time
)

Add imports, define your data structures and derive a codec:

import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._

sealed trait Side
case object Buy extends Side
case object Sell extends Side

case class BitmexTradeData(
  foreignNotional: Option[Int],
  grossValue: Option[Int],
  homeNotional: Option[Double],
  price: Double,
  side: Side,
  size: Double,
  symbol: String,
  tickDirection: String,
  timestamp: Instant,
  trdMatchID: String  // <-- Here you can use java.util.UUID for validation, less memory allocations and more efficient parsing/serialization
)

implicit val codec: JsonValueCodec[BitmexTradeData] =
  JsonCodecMaker.make(CodecMakerConfig.withDiscriminatorFieldName(None))

After that you can parse and print your input:

val data = readFromArray("""{
                           |  "timestamp": "2019-10-17T01:34:00.000Z",
                           |  "symbol": ".BTRXXBT",
                           |  "side": "Buy",
                           |  "size": 0,
                           |  "price": 0.00000187,
                           |  "tickDirection": "PlusTick",
                           |  "trdMatchID": "00000000-0000-0000-0000-000000000000",
                           |  "grossValue": null,
                           |  "homeNotional": null,
                           |  "foreignNotional": null
                           |}""".stripMargin.getBytes("UTF-8"))

println(data)

Output will be:

BitmexTradeData(None,None,None,1.87E-6,Buy,0.0,.BTRXXBT,PlusTick,2019-10-17T01:34:00Z,00000000-0000-0000-0000-000000000000)