Skip to content

Commit ba4be9c

Browse files
committed
Fix a regression introduced in 2.31.2 in the jsoniter-scala-circe's decoder for Long when decoding from io.circe.JsonBigDecimal values
1 parent 5fcc345 commit ba4be9c

File tree

2 files changed

+145
-94
lines changed

2 files changed

+145
-94
lines changed

jsoniter-scala-circe/shared/src/main/scala/io/circe/JsoniterScalaCodec.scala

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package io.circe
33
import com.github.plokhotnyuk.jsoniter_scala.core._
44
import io.circe.Decoder.Result
55
import io.circe.Json._
6-
import io.circe.numbers.BiggerDecimal
7-
8-
import java.math.{BigInteger, RoundingMode}
6+
import java.math.RoundingMode
97
import java.nio.charset.StandardCharsets
108
import java.util
119
import scala.collection.immutable.VectorBuilder
@@ -15,7 +13,6 @@ object JsoniterScalaCodec {
1513
/**
1614
* Default number parser that detects integers vs floating-point values
1715
* and chooses an appropriate JSON number representation.
18-
*
1916
* @return a JSON number value
2017
*/
2118
val defaultNumberParser: JsonReader => Json = in => new JNumber({
@@ -72,9 +69,13 @@ object JsoniterScalaCodec {
7269
}
7370
}
7471

75-
private[this] val longMin = BigInteger.valueOf(Long.MinValue)
72+
private[this] val intMin = java.math.BigDecimal.valueOf(Int.MinValue)
73+
74+
private[this] val intMax = java.math.BigDecimal.valueOf(Int.MaxValue)
75+
76+
private[this] val longMin = java.math.BigDecimal.valueOf(Long.MinValue)
7677

77-
private[this] val longMax = BigInteger.valueOf(Long.MaxValue)
78+
private[this] val longMax = java.math.BigDecimal.valueOf(Long.MaxValue)
7879

7980
/**
8081
* Converts an ASCII byte array to a JSON string.
@@ -107,9 +108,9 @@ object JsoniterScalaCodec {
107108
val b = l.toByte
108109
if (b == l) return new Right(b)
109110
case jbd: JsonBigDecimal =>
110-
val bi = longValueExact(jbd.value)
111-
if (bi ne null) {
112-
val l = bi.longValue
111+
val bd = intValueExact(jbd.value)
112+
if (bd ne null) {
113+
val l = bd.intValue
113114
val b = l.toByte
114115
if (b == l) return new Right(b)
115116
}
@@ -143,9 +144,9 @@ object JsoniterScalaCodec {
143144
val s = l.toShort
144145
if (s == l) return new Right(s)
145146
case jbd: JsonBigDecimal =>
146-
val bi = longValueExact(jbd.value)
147-
if (bi ne null) {
148-
val l = bi.longValue
147+
val bd = intValueExact(jbd.value)
148+
if (bd ne null) {
149+
val l = bd.intValue
149150
val s = l.toShort
150151
if (s == l) return new Right(s)
151152
}
@@ -179,12 +180,8 @@ object JsoniterScalaCodec {
179180
val i = l.toInt
180181
if (i == l) return new Right(i)
181182
case jbd: JsonBigDecimal =>
182-
val bi = longValueExact(jbd.value)
183-
if (bi ne null) {
184-
val l = bi.longValue
185-
val i = l.toInt
186-
if (i == l) return new Right(i)
187-
}
183+
val bd = intValueExact(jbd.value)
184+
if (bd ne null) return new Right(bd.intValue)
188185
case y =>
189186
val ol = y.toLong
190187
if (ol ne None) {
@@ -212,12 +209,8 @@ object JsoniterScalaCodec {
212209
n.value match {
213210
case jl: JsonLong => return new Right(jl.value)
214211
case jbd: JsonBigDecimal =>
215-
val bi = longValueExact(jbd.value)
216-
if (bi ne null) {
217-
val l = bi.longValue
218-
val s = l.toShort
219-
if (s == l) return new Right(s)
220-
}
212+
val bd = longValueExact(jbd.value)
213+
if (bd ne null) return new Right(bd.longValue)
221214
case x =>
222215
val ol = x.toLong
223216
if (ol ne None) return new Right(ol.get)
@@ -315,16 +308,27 @@ object JsoniterScalaCodec {
315308
private[this] def fail(c: HCursor): Result[BigDecimal] = new Left(DecodingFailure("BigDecimal", c.history))
316309
}
317310

318-
private[this] def longValueExact(bd: java.math.BigDecimal): BigInteger =
311+
private[this] def intValueExact(bd: java.math.BigDecimal): java.math.BigDecimal =
312+
if (bd.signum != 0) {
313+
var p = bd.precision
314+
val s = bd.scale
315+
if (p <= s || p - 10 > s) return null
316+
val bd0 = bd.setScale(0, RoundingMode.UNNECESSARY)
317+
p = bd0.precision
318+
if (p > 10 || p == 10 && (bd0.compareTo(intMin) < 0 || bd0.compareTo(intMax) > 0)) return null
319+
bd0
320+
} else java.math.BigDecimal.ZERO
321+
322+
private[this] def longValueExact(bd: java.math.BigDecimal): java.math.BigDecimal =
319323
if (bd.signum != 0) {
320-
val p = bd.precision
324+
var p = bd.precision
321325
val s = bd.scale
322326
if (p <= s || p - 19 > s) return null
323327
val bd0 = bd.setScale(0, RoundingMode.UNNECESSARY)
324-
val bi = bd0.unscaledValue
325-
if (bd0.precision >= 19 || bi.compareTo(longMin) < 0 || bi.compareTo(longMax) > 0) return null
326-
bi
327-
} else BigInteger.ZERO
328+
p = bd0.precision
329+
if (p > 19 || p == 19 && (bd0.compareTo(longMin) < 0 || bd0.compareTo(longMax) > 0)) return null
330+
bd0
331+
} else java.math.BigDecimal.ZERO
328332
}
329333

330334
/**

0 commit comments

Comments
 (0)