Play Json BigDecimal type lost precision when writing

302 views
Skip to first unread message

Tianhao Li

unread,
Dec 26, 2015, 11:29:26 PM12/26/15
to Melbourne Scala User Group

For example I have following code

case class Person(name: String, pay: BigDecimal)
val person = Person(name = "Scala", pay = BigDecimal(10.00))
Json.toJson(person))

The JSON result should be

{
  "name": "Scala"
  "pay": 10.00
}

However the result is not as expected that's:

{
  "name": "Scala"
  "pay": 10
}

This issue should be fixed with the precision we specified.


Even I create a customized implicit writes it still can't get the number I wanted.


implicit val bigdecimalWrites = new Writes[BigDecimal] {
    def writes(o: BigDecimal): JsValue = {
      JsNumber(o.setScala(2))
    }
  }

Bryan Murphy

unread,
Jan 2, 2016, 4:56:52 AM1/2/16
to Melbourne Scala User Group

I don’t think you can make assumptions about the precision of a JSON number in its rendered string form.


When the JSON is rendered to a string it is converted from the language specific JSON representation (ie Scala JsValue case classes) into the JSON text format.  The JSON number format (from the language independent JSON specification perspective) does not have a concept of precision (you can have a million digits if you want) so the renderer can choose to represent 10.00 as 10 since they are the same “number”.  Changing the Scala precision of the BigDecimal in JsNumber does not necessarily influence what the renderer chooses to do (it might but that is an implementation detail).  Different renderers (eg Play JSON, Spray JSON, Argonaut, etc) may do different things and still conform to the JSON spec.


In the case of Play JSON I had a quick look at the code and when converting a JsValue to a string it appears to have a special case for truncating trailing zeros in JsNumber’s.


If the precision is important to you to be saved into the json you may need to add an extra field or try another Json implementation or there may be a way to replace the default serializer within Play - there looks to be a mechanism to register modules to handle the serialization but I am not exactly sure how that works.


Bryan

Toby Corkindale

unread,
Jan 5, 2016, 1:59:29 AM1/5/16
to scala...@googlegroups.com
It's arguable that you haven't lost any precision when going from 10.00 to 10. They are precisely the same value.

Are you just wanting to make sure that currency values are printed to two decimal places? In that case, I suggest you handle that elsewhere, on the user interface side of things, not the API side.

Toby

--
You received this message because you are subscribed to the Google Groups "Melbourne Scala User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-melb+...@googlegroups.com.
To post to this group, send email to scala...@googlegroups.com.
Visit this group at https://groups.google.com/group/scala-melb.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages