circe 0.5.4
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+2147483649If 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 = falseThe 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 = falseDecoding these values into Double, BigDecimal, Long, or any other representation would result in correct comparisons.