Skip to content

circe 0.5.4

Choose a tag to compare

@travisbrown travisbrown released this 17 Oct 19:34

This release introduces Scala.js artifacts for circe-optics (thanks, Eric Merritt), and includes two backported bug fixes related to JSON number parsing.

While most users should not be affected by these two bugs, we do encourage everyone to update to 0.5.4, which is fully binary compatible with previous 0.5 releases.

The first issue involves very large BigDecimal values. If you try to parse a number with an exponent larger than Int.MaxValue directly into a BigDecimal, you'll get a NumberFormatException:

scala> val bigDecimal = BigDecimal(s"1e${ Int.MaxValue.toLong + 1L }")
java.lang.NumberFormatException
  at java.math.BigDecimal.<init>(BigDecimal.java:491)
...

It is possible to construct large values like this, though, by moving some of the zeros to the left of the decimal point:

scala> val bigDecimal = BigDecimal(s"100e${ Int.MaxValue }")
bigDecimal: scala.math.BigDecimal = 1.0E+2147483649

If you have a BigDecimal value like this, and you use BiggerDecimal.fromBigDecimal to convert it into a BiggerDecimal, you'll get an incorrect value in 0.5.3 or earlier:

scala> import io.circe.numbers.{ BiggerDecimal, NumberParsing }
import io.circe.numbers.BiggerDecimal

scala> val fromBigDecimal = BiggerDecimal.fromBigDecimal(bigDecimal.bigDecimal)
fromBigDecimal: io.circe.numbers.BiggerDecimal = 1e2147483645

scala> val Some(fromString) = NumberParsing.parseBiggerDecimal(bigDecimal.toString)
fromString: io.circe.numbers.BiggerDecimal = 1e2147483649

scala> fromBigDecimal == fromString
res0: Boolean = false

The second bug involves situations where multiples of ten with zeros after a decimal point were not being correctly converted into canonical form. While this does not affect decoding, it does affect equality comparisons for JsonNumber:

scala> import io.circe.{ Json, JsonNumber }
import io.circe.{Json, JsonNumber}

scala> val fromDouble = Json.fromDouble(10.0)
fromDouble: Option[io.circe.Json] = Some(10.0)

scala> val fromString = Json.fromJsonNumber(JsonNumber.unsafeDecimal("10.0"))
fromString: io.circe.Json = 10.0

scala> fromDouble.get == fromString
res0: Boolean = false

Decoding these values into Double, BigDecimal, Long, or any other representation would result in correct comparisons.