Skip to content

Commit fb1e68c

Browse files
committed
More efficient failing when decoding too big io.circe.JNumber and io.circe.JString values using jsoniter-scala-circe's codecs for numbers
1 parent 4d8850d commit fb1e68c

File tree

2 files changed

+126
-43
lines changed

2 files changed

+126
-43
lines changed

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

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ 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}
69
import java.nio.charset.StandardCharsets
710
import java.util
811
import scala.collection.immutable.VectorBuilder
@@ -69,6 +72,10 @@ object JsoniterScalaCodec {
6972
}
7073
}
7174

75+
private[this] val longMin = BigInteger.valueOf(Long.MinValue)
76+
77+
private[this] val longMax = BigInteger.valueOf(Long.MaxValue)
78+
7279
/**
7380
* Converts an ASCII byte array to a JSON string.
7481
*
@@ -99,6 +106,13 @@ object JsoniterScalaCodec {
99106
val l = jl.value
100107
val b = l.toByte
101108
if (b == l) return new Right(b)
109+
case jbd: JsonBigDecimal =>
110+
val bi = longValueExact(jbd.value)
111+
if (bi ne null) {
112+
val l = bi.longValue
113+
val b = l.toByte
114+
if (b == l) return new Right(b)
115+
}
102116
case y =>
103117
val ol = y.toLong
104118
if (ol ne None) {
@@ -109,7 +123,7 @@ object JsoniterScalaCodec {
109123
}
110124
fail(c)
111125
case s: JString => try new Right(fromString(s.value)) catch {
112-
case NonFatal(_) => fail(c)
126+
case e if NonFatal(e) => fail(c)
113127
}
114128
case _ => fail(c)
115129
}
@@ -128,6 +142,13 @@ object JsoniterScalaCodec {
128142
val l = jl.value
129143
val s = l.toShort
130144
if (s == l) return new Right(s)
145+
case jbd: JsonBigDecimal =>
146+
val bi = longValueExact(jbd.value)
147+
if (bi ne null) {
148+
val l = bi.longValue
149+
val s = l.toShort
150+
if (s == l) return new Right(s)
151+
}
131152
case y =>
132153
val ol = y.toLong
133154
if (ol ne None) {
@@ -138,7 +159,7 @@ object JsoniterScalaCodec {
138159
}
139160
fail(c)
140161
case s: JString => try new Right(fromString(s.value)) catch {
141-
case NonFatal(_) => fail(c)
162+
case e if NonFatal(e) => fail(c)
142163
}
143164
case _ => fail(c)
144165
}
@@ -157,6 +178,13 @@ object JsoniterScalaCodec {
157178
val l = jl.value
158179
val i = l.toInt
159180
if (i == l) return new Right(i)
181+
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+
}
160188
case y =>
161189
val ol = y.toLong
162190
if (ol ne None) {
@@ -167,7 +195,7 @@ object JsoniterScalaCodec {
167195
}
168196
fail(c)
169197
case s: JString => try new Right(fromString(s.value)) catch {
170-
case NonFatal(_) => fail(c)
198+
case e if NonFatal(e) => fail(c)
171199
}
172200
case _ => fail(c)
173201
}
@@ -177,17 +205,26 @@ object JsoniterScalaCodec {
177205

178206
private[this] def fail(c: HCursor): Result[Int] = new Left(DecodingFailure("Int", c.history))
179207
}
208+
180209
def longCodec(fromString: String => Long): Codec[Long] = new Codec[Long] {
181210
final def apply(c: HCursor): Result[Long] = c.value match {
182-
case n: JNumber => n.value match {
183-
case jl: JsonLong => new Right(jl.value)
184-
case x =>
185-
val ol = x.toLong
186-
if (ol ne None) new Right(ol.get)
187-
else fail(c)
188-
}
211+
case n: JNumber =>
212+
n.value match {
213+
case jl: JsonLong => return new Right(jl.value)
214+
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+
}
221+
case x =>
222+
val ol = x.toLong
223+
if (ol ne None) return new Right(ol.get)
224+
}
225+
fail(c)
189226
case s: JString => try new Right(fromString(s.value)) catch {
190-
case NonFatal(_) => fail(c)
227+
case e if NonFatal(e) => fail(c)
191228
}
192229
case _ => fail(c)
193230
}
@@ -202,7 +239,7 @@ object JsoniterScalaCodec {
202239
final def apply(c: HCursor): Result[Float] = c.value match {
203240
case n: JNumber => new Right(n.value.toFloat)
204241
case s: JString => try new Right(fromString(s.value)) catch {
205-
case NonFatal(_) => fail(c)
242+
case e if NonFatal(e) => fail(c)
206243
}
207244
case _ => fail(c)
208245
}
@@ -217,7 +254,7 @@ object JsoniterScalaCodec {
217254
final def apply(c: HCursor): Result[Double] = c.value match {
218255
case n: JNumber => new Right(n.value.toDouble)
219256
case s: JString => try new Right(fromString(s.value)) catch {
220-
case NonFatal(_) => fail(c)
257+
case e if NonFatal(e) => fail(c)
221258
}
222259
case _ => fail(c)
223260
}
@@ -227,6 +264,7 @@ object JsoniterScalaCodec {
227264

228265
private[this] def fail(c: HCursor): Result[Double] = new Left(DecodingFailure("Double", c.history))
229266
}
267+
230268
def bigIntCodec(fromString: String => BigInt): Codec[BigInt] = new Codec[BigInt] {
231269
final def apply(c: HCursor): Result[BigInt] = try c.value match {
232270
case n: JNumber => n.value match {
@@ -244,7 +282,7 @@ object JsoniterScalaCodec {
244282
case s: JString => new Right(fromString(s.value))
245283
case _ => fail(c)
246284
} catch {
247-
case NonFatal(_) => fail(c)
285+
case e if NonFatal(e) => fail(c)
248286
}
249287

250288
@inline
@@ -266,7 +304,7 @@ object JsoniterScalaCodec {
266304
}
267305
}
268306
case s: JString => try new Right(fromString(s.value)) catch {
269-
case NonFatal(_) => fail(c)
307+
case e if NonFatal(e) => fail(c)
270308
}
271309
case _ => fail(c)
272310
}
@@ -276,6 +314,17 @@ object JsoniterScalaCodec {
276314

277315
private[this] def fail(c: HCursor): Result[BigDecimal] = new Left(DecodingFailure("BigDecimal", c.history))
278316
}
317+
318+
private[this] def longValueExact(bd: java.math.BigDecimal): BigInteger =
319+
if (bd.signum != 0) {
320+
val p = bd.precision
321+
val s = bd.scale
322+
if (p <= s || p - 19 > s) return null
323+
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
279328
}
280329

281330
/**

jsoniter-scala-circe/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/circe/CirceCodecsSpec.scala

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,72 +12,102 @@ import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
1212
class CirceCodecsSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks {
1313
"CirceCodecsSpec codecs" should {
1414
"decode and encode Byte" in {
15-
Decoder[Byte].decodeJson(Json.fromFloatOrNull(1.0f)).getOrElse(0.toByte) shouldBe 1.toByte
16-
Decoder[Byte].decodeJson(Json.fromDoubleOrNull(1.0)).getOrElse(0.toByte) shouldBe 1.toByte
17-
Decoder[Byte].decodeJson(Json.fromBigInt(1)).getOrElse(0.toByte) shouldBe 1.toByte
18-
Decoder[Byte].decodeJson(Json.fromBigDecimal(1.0)).getOrElse(0.toByte) shouldBe 1.toByte
19-
Decoder[Byte].decodeJson(Json.fromString("001")).getOrElse(0.toByte) shouldBe 1.toByte
15+
Decoder[Byte].decodeJson(Json.fromFloatOrNull(1.0f)) shouldBe Right(1.toByte)
16+
Decoder[Byte].decodeJson(Json.fromDoubleOrNull(1.0)) shouldBe Right(1.toByte)
17+
Decoder[Byte].decodeJson(Json.fromBigInt(1)) shouldBe Right(1.toByte)
18+
Decoder[Byte].decodeJson(Json.fromBigDecimal(1.0)) shouldBe Right(1.toByte)
19+
Decoder[Byte].decodeJson(Json.fromString("001")) shouldBe Right(1.toByte)
2020
Decoder[Byte].decodeJson(Json.fromString(" 1")) shouldBe Left(DecodingFailure("Byte", Nil))
2121
Decoder[Byte].decodeJson(Json.fromString("1 ")) shouldBe Left(DecodingFailure("Byte", Nil))
22+
Decoder[Byte].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("Byte", Nil))
23+
Decoder[Byte].decodeJson(Json.fromString("128")) shouldBe Left(DecodingFailure("Byte", Nil))
24+
Decoder[Byte].decodeJson(Json.fromString("-129")) shouldBe Left(DecodingFailure("Byte", Nil))
25+
Decoder[Byte].decodeJson(Json.fromBigDecimal(0.123)) shouldBe Left(DecodingFailure("Byte", Nil))
26+
Decoder[Byte].decodeJson(Json.fromBigDecimal(BigDecimal("92233720368547758080"))) shouldBe Left(DecodingFailure("Byte", Nil))
27+
Decoder[Byte].decodeJson(Json.fromBigDecimal(BigDecimal("9223372036854775808"))) shouldBe Left(DecodingFailure("Byte", Nil))
28+
Decoder[Byte].decodeJson(Json.fromBigDecimal(BigDecimal("-9223372036854775809"))) shouldBe Left(DecodingFailure("Byte", Nil))
29+
Decoder[Byte].decodeJson(Json.fromBigDecimal(BigDecimal("0000000000000000000"))) shouldBe Right(0.toByte)
2230
forAll(arbitrary[Byte], minSuccessful(10000)) { x =>
23-
Decoder[Byte].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe x
31+
Decoder[Byte].decodeJson(Json.fromString(x.toString)) shouldBe Right(x)
2432
}
2533
forAll(arbitrary[Byte], minSuccessful(10000)) { x =>
26-
Decoder[Byte].decodeJson(Json.fromInt(x)).getOrElse(null) shouldBe x
34+
Decoder[Byte].decodeJson(Json.fromInt(x)) shouldBe Right(x)
2735
}
2836
forAll(arbitrary[Byte], minSuccessful(10000)) { x =>
2937
Encoder[Byte].apply(x) shouldBe Json.fromInt(x)
3038
}
3139
}
3240
"decode and encode Short" in {
33-
Decoder[Short].decodeJson(Json.fromFloatOrNull(1.0f)).getOrElse(0.toShort) shouldBe 1.toShort
34-
Decoder[Short].decodeJson(Json.fromDoubleOrNull(1.0)).getOrElse(0.toShort) shouldBe 1.toShort
35-
Decoder[Short].decodeJson(Json.fromBigInt(1)).getOrElse(0.toShort) shouldBe 1.toShort
36-
Decoder[Short].decodeJson(Json.fromBigDecimal(1.0)).getOrElse(0.toShort) shouldBe 1.toShort
37-
Decoder[Short].decodeJson(Json.fromString("001")).getOrElse(0.toShort) shouldBe 1.toShort
41+
Decoder[Short].decodeJson(Json.fromFloatOrNull(1.0f)) shouldBe Right(1.toShort)
42+
Decoder[Short].decodeJson(Json.fromDoubleOrNull(1.0)) shouldBe Right(1.toShort)
43+
Decoder[Short].decodeJson(Json.fromBigInt(1)) shouldBe Right(1.toShort)
44+
Decoder[Short].decodeJson(Json.fromBigDecimal(1.0)) shouldBe Right(1.toShort)
45+
Decoder[Short].decodeJson(Json.fromString("001")) shouldBe Right(1.toShort)
3846
Decoder[Short].decodeJson(Json.fromString(" 1")) shouldBe Left(DecodingFailure("Short", Nil))
3947
Decoder[Short].decodeJson(Json.fromString("1 ")) shouldBe Left(DecodingFailure("Short", Nil))
48+
Decoder[Short].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("Short", Nil))
49+
Decoder[Short].decodeJson(Json.fromString("32768")) shouldBe Left(DecodingFailure("Short", Nil))
50+
Decoder[Short].decodeJson(Json.fromString("-32769")) shouldBe Left(DecodingFailure("Short", Nil))
51+
Decoder[Short].decodeJson(Json.fromBigDecimal(0.123)) shouldBe Left(DecodingFailure("Short", Nil))
52+
Decoder[Short].decodeJson(Json.fromBigDecimal(BigDecimal("92233720368547758080"))) shouldBe Left(DecodingFailure("Short", Nil))
53+
Decoder[Short].decodeJson(Json.fromBigDecimal(BigDecimal("9223372036854775808"))) shouldBe Left(DecodingFailure("Short", Nil))
54+
Decoder[Short].decodeJson(Json.fromBigDecimal(BigDecimal("-9223372036854775809"))) shouldBe Left(DecodingFailure("Short", Nil))
55+
Decoder[Short].decodeJson(Json.fromBigDecimal(BigDecimal("0000000000000000000"))) shouldBe Right(0.toShort)
4056
forAll(arbitrary[Short], minSuccessful(10000)) { x =>
41-
Decoder[Short].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe x
57+
Decoder[Short].decodeJson(Json.fromString(x.toString)) shouldBe Right(x)
4258
}
4359
forAll(arbitrary[Short], minSuccessful(10000)) { x =>
44-
Decoder[Short].decodeJson(Json.fromInt(x)).getOrElse(null) shouldBe x
60+
Decoder[Short].decodeJson(Json.fromInt(x)) shouldBe Right(x)
4561
}
4662
forAll(arbitrary[Short], minSuccessful(10000)) { x =>
4763
Encoder[Short].apply(x) shouldBe Json.fromInt(x)
4864
}
4965
}
5066
"decode and encode Int" in {
51-
Decoder[Int].decodeJson(Json.fromFloatOrNull(1.0f)).getOrElse(0) shouldBe 1
52-
Decoder[Int].decodeJson(Json.fromDoubleOrNull(1.0)).getOrElse(0) shouldBe 1
53-
Decoder[Int].decodeJson(Json.fromBigInt(1)).getOrElse(0) shouldBe 1
54-
Decoder[Int].decodeJson(Json.fromBigDecimal(1.0)).getOrElse(0) shouldBe 1
55-
Decoder[Int].decodeJson(Json.fromString("001")).getOrElse(0) shouldBe 1
67+
Decoder[Int].decodeJson(Json.fromFloatOrNull(1.0f)) shouldBe Right(1)
68+
Decoder[Int].decodeJson(Json.fromDoubleOrNull(1.0)) shouldBe Right(1)
69+
Decoder[Int].decodeJson(Json.fromBigInt(1)) shouldBe Right(1)
70+
Decoder[Int].decodeJson(Json.fromBigDecimal(1.0)) shouldBe Right(1)
71+
Decoder[Int].decodeJson(Json.fromString("001")) shouldBe Right(1)
5672
Decoder[Int].decodeJson(Json.fromString(" 1")) shouldBe Left(DecodingFailure("Int", Nil))
5773
Decoder[Int].decodeJson(Json.fromString("1 ")) shouldBe Left(DecodingFailure("Int", Nil))
74+
Decoder[Int].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("Int", Nil))
75+
Decoder[Int].decodeJson(Json.fromString("2147483648")) shouldBe Left(DecodingFailure("Int", Nil))
76+
Decoder[Int].decodeJson(Json.fromString("-2147483649")) shouldBe Left(DecodingFailure("Int", Nil))
77+
Decoder[Int].decodeJson(Json.fromBigDecimal(0.123)) shouldBe Left(DecodingFailure("Int", Nil))
78+
Decoder[Int].decodeJson(Json.fromBigDecimal(BigDecimal("92233720368547758080"))) shouldBe Left(DecodingFailure("Int", Nil))
79+
Decoder[Int].decodeJson(Json.fromBigDecimal(BigDecimal("9223372036854775808"))) shouldBe Left(DecodingFailure("Int", Nil))
80+
Decoder[Int].decodeJson(Json.fromBigDecimal(BigDecimal("-9223372036854775809"))) shouldBe Left(DecodingFailure("Int", Nil))
81+
Decoder[Int].decodeJson(Json.fromBigDecimal(BigDecimal("0000000000000000000"))) shouldBe Right(0)
5882
forAll(arbitrary[Int], minSuccessful(10000)) { x =>
59-
Decoder[Int].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe x
83+
Decoder[Int].decodeJson(Json.fromString(x.toString)) shouldBe Right(x)
6084
}
6185
forAll(arbitrary[Int], minSuccessful(10000)) { x =>
62-
Decoder[Int].decodeJson(Json.fromInt(x)).getOrElse(null) shouldBe x
86+
Decoder[Int].decodeJson(Json.fromInt(x)) shouldBe Right(x)
6387
}
6488
forAll(arbitrary[Int], minSuccessful(10000)) { x =>
6589
Encoder[Int].apply(x) shouldBe Json.fromInt(x)
6690
}
6791
}
6892
"decode and encode Long" in {
69-
Decoder[Long].decodeJson(Json.fromFloatOrNull(1.0f)).getOrElse(0L) shouldBe 1L
70-
Decoder[Long].decodeJson(Json.fromDoubleOrNull(1.0)).getOrElse(0L) shouldBe 1L
71-
Decoder[Long].decodeJson(Json.fromBigInt(1)).getOrElse(0L) shouldBe 1L
72-
Decoder[Long].decodeJson(Json.fromBigDecimal(1.0)).getOrElse(0L) shouldBe 1L
73-
Decoder[Long].decodeJson(Json.fromString("001")).getOrElse(0L) shouldBe 1L
93+
Decoder[Long].decodeJson(Json.fromFloatOrNull(1.0f)) shouldBe Right(1L)
94+
Decoder[Long].decodeJson(Json.fromDoubleOrNull(1.0)) shouldBe Right(1L)
95+
Decoder[Long].decodeJson(Json.fromBigInt(1)) shouldBe Right(1L)
96+
Decoder[Long].decodeJson(Json.fromBigDecimal(1.0)) shouldBe Right(1L)
97+
Decoder[Long].decodeJson(Json.fromString("001")) shouldBe Right(1L)
7498
Decoder[Long].decodeJson(Json.fromString(" 1")) shouldBe Left(DecodingFailure("Long", Nil))
7599
Decoder[Long].decodeJson(Json.fromString("1 ")) shouldBe Left(DecodingFailure("Long", Nil))
100+
Decoder[Long].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("Long", Nil))
101+
Decoder[Long].decodeJson(Json.fromBigDecimal(0.123)) shouldBe Left(DecodingFailure("Long", Nil))
102+
Decoder[Long].decodeJson(Json.fromBigDecimal(BigDecimal("92233720368547758080"))) shouldBe Left(DecodingFailure("Long", Nil))
103+
Decoder[Long].decodeJson(Json.fromBigDecimal(BigDecimal("9223372036854775808"))) shouldBe Left(DecodingFailure("Long", Nil))
104+
Decoder[Long].decodeJson(Json.fromBigDecimal(BigDecimal("-9223372036854775809"))) shouldBe Left(DecodingFailure("Long", Nil))
105+
Decoder[Long].decodeJson(Json.fromBigDecimal(BigDecimal("0000000000000000000"))) shouldBe Right(0)
76106
forAll(arbitrary[Long], minSuccessful(10000)) { x =>
77-
Decoder[Long].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe x
107+
Decoder[Long].decodeJson(Json.fromString(x.toString)) shouldBe Right(x)
78108
}
79109
forAll(arbitrary[Long], minSuccessful(10000)) { x =>
80-
Decoder[Long].decodeJson(Json.fromLong(x)).getOrElse(null) shouldBe x
110+
Decoder[Long].decodeJson(Json.fromLong(x)) shouldBe Right(x)
81111
}
82112
forAll(arbitrary[Long], minSuccessful(10000)) { x =>
83113
Encoder[Long].apply(x) shouldBe Json.fromLong(x)
@@ -91,6 +121,7 @@ class CirceCodecsSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyC
91121
Decoder[Float].decodeJson(Json.fromString("001.0")).getOrElse(0.0f) shouldBe 1.0f
92122
Decoder[Float].decodeJson(Json.fromString(" 1.0")) shouldBe Left(DecodingFailure("Float", Nil))
93123
Decoder[Float].decodeJson(Json.fromString("1.0 ")) shouldBe Left(DecodingFailure("Float", Nil))
124+
Decoder[Float].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("Float", Nil))
94125
forAll(arbitrary[Float], minSuccessful(10000)) { x =>
95126
Decoder[Float].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe x
96127
}
@@ -109,6 +140,7 @@ class CirceCodecsSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyC
109140
Decoder[Double].decodeJson(Json.fromString("001.0")).getOrElse(0.0) shouldBe 1.0
110141
Decoder[Double].decodeJson(Json.fromString(" 1.0")) shouldBe Left(DecodingFailure("Double", Nil))
111142
Decoder[Double].decodeJson(Json.fromString("1.0 ")) shouldBe Left(DecodingFailure("Double", Nil))
143+
Decoder[Double].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("Double", Nil))
112144
forAll(arbitrary[Double], minSuccessful(10000)) { x =>
113145
Decoder[Double].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe x
114146
}
@@ -127,6 +159,7 @@ class CirceCodecsSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyC
127159
Decoder[BigInt].decodeJson(Json.fromString("001")).getOrElse(null) shouldBe BigInt(1)
128160
Decoder[BigInt].decodeJson(Json.fromString(" 1")) shouldBe Left(DecodingFailure("BigInt", Nil))
129161
Decoder[BigInt].decodeJson(Json.fromString("1 ")) shouldBe Left(DecodingFailure("BigInt", Nil))
162+
Decoder[BigInt].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("BigInt", Nil))
130163
forAll(arbitrary[BigInt], minSuccessful(10000)) { x =>
131164
Decoder[BigInt].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe x
132165
}
@@ -145,6 +178,7 @@ class CirceCodecsSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyC
145178
Decoder[BigDecimal].decodeJson(Json.fromString("001.0")).getOrElse(null) shouldBe BigDecimal(1.0)
146179
Decoder[BigDecimal].decodeJson(Json.fromString(" 1.0")) shouldBe Left(DecodingFailure("BigDecimal", Nil))
147180
Decoder[BigDecimal].decodeJson(Json.fromString("1.0 ")) shouldBe Left(DecodingFailure("BigDecimal", Nil))
181+
Decoder[BigDecimal].decodeJson(Json.fromBoolean(true)) shouldBe Left(DecodingFailure("BigDecimal", Nil))
148182
forAll(arbitrary[BigDecimal], minSuccessful(10000)) { x =>
149183
val y = x.apply(JsonReader.bigDecimalMathContext)
150184
Decoder[BigDecimal].decodeJson(Json.fromString(x.toString)).getOrElse(null) shouldBe y

0 commit comments

Comments
 (0)