Search code examples
jsonscalabigdecimalcirce

How to avoid scientific notation in circe JSON serialization


Let's say I have the next case class:

case class Person(id: String, money: BigDecimal)

object Person {
  implicit val encoder: Encoder[Person] = Encoder.forProduct2("ID", "Money")(u =>
    (u.id, u.money))

I want to serialize instances of the Person class to JSON, so when I evaluate the asJson from circe, I get the result in scientific notation:

{
    "ID" : "123",
    "VALOR_SAP" : 2.7E+7
}

Why do this happens? I think the reason is because the default to string of BigDecimal automatically format to scientific notation.

What could I do to avoid this? May be creating another type which extends from BigDecimal and overriding the toString?


Solution

  • I assume that you use scala.math.BigDecimal, for java.math.BigDecimal code is similar. The way to change how objects are serialized is to provide corresponding implicit Encoder object. Unfortunately both Json and JsonNumber hierachies are sealed, so there is no very clean solution but you still can use JsonNumber.fromDecimalStringUnsafe that implements toString to just return any string you passed in. So you can do something like this:

    case class Person(id: String, money: BigDecimal)
    
    object Person {
      implicit final val bigDecimalAsPlainStringEncoder: Encoder[BigDecimal] = new Encoder[BigDecimal] {
        final def apply(value: BigDecimal): Json = Json.fromJsonNumber(JsonNumber.fromDecimalStringUnsafe(value.bigDecimal.toPlainString))
      }
    
      implicit val encoder: Encoder[Person] = Encoder.forProduct2("ID", "Money")(u => (u.id, u.money))
    
    }