Skip to content

Commit 82c1d07

Browse files
committed
Fix #78 & fix #79 & fix #80 by refactoring of low-level API of the reader + fix of code generation for options
1 parent 4280cec commit 82c1d07

File tree

5 files changed

+19
-12
lines changed

5 files changed

+19
-12
lines changed

core/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -472,11 +472,10 @@ final class JsonReader private[jsoniter_scala](
472472
x
473473
}
474474

475-
def readNullOrError[A](default: A): A = parseNullOrError(default, "expected null", head)
476-
477-
def readNullOrNumberError[A](default: A, pos: Int): A =
478-
if (default == null) numberError(pos - 1)
479-
else parseNullOrError(default, "expected number or null", pos)
475+
def readNullOrError[A](default: A, msg: String): A =
476+
if (default == null) throw new IllegalArgumentException("'default' should not be null")
477+
else if (isCurrentToken('n', head)) parseNullOrError(default, msg, head)
478+
else decodeError(msg)
480479

481480
def readNullOrTokenError[A](default: A, b: Byte): A =
482481
if (default == null) tokenError(b)
@@ -1262,6 +1261,10 @@ final class JsonReader private[jsoniter_scala](
12621261
case ex: NumberFormatException => decodeError("illegal number", head - 1, ex)
12631262
}
12641263

1264+
private def readNullOrNumberError[A](default: A, pos: Int): A =
1265+
if (default == null) numberError(pos - 1)
1266+
else parseNullOrError(default, "expected number or null", pos)
1267+
12651268
private def numberError(pos: Int): Nothing = decodeError("illegal number", pos)
12661269

12671270
private def leadingZeroError(pos: Int): Nothing = decodeError("illegal number with leading zero", pos)

macros/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMaker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ object JsonCodecMaker {
481481
q"new $tpe(${genReadVal(tpe1, nullValue(tpe1), isStringified)})"
482482
} else if (tpe <:< typeOf[Option[_]]) withDecoderFor(methodKey, default) {
483483
val tpe1 = typeArg1(tpe)
484-
q"""if (in.isNextToken('n')) in.readNullOrError(None)
484+
q"""if (in.isNextToken('n')) in.readNullOrError(default, "expected value or null")
485485
else {
486486
in.rollbackToken()
487487
Some(${genReadVal(tpe1, nullValue(tpe1), isStringified)})

macros/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMakerSpec.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,12 @@ class JsonCodecMakerSpec extends WordSpec with Matchers {
491491
verifySerDeser(codecOfStringifiedOption, Some(BigInt(123)), "\"123\"".getBytes)
492492
verifySerDeser(codecOfStringifiedOption, None, "null".getBytes)
493493
}
494+
"throw parse exception in case of unexpected value for option" in {
495+
val codecOfStringOption = make[Option[String]](CodecMakerConfig())
496+
assert(intercept[JsonParseException] {
497+
verifyDeser(codecOfStringOption, Option("VVV"), """no!!!""".getBytes)
498+
}.getMessage.contains("expected value or null, offset: 0x00000001"))
499+
}
494500
"serialize and deserialize case classes with tuples" in {
495501
verifySerDeser(codecOfTuples, Tuples((1, 2.2, List('V')), ("VVV", 3, Some(LocationType.GPS))),
496502
"""{"t1":[1,2.2,["V"]],"t2":["VVV",3,"GPS"]}""".getBytes)
@@ -782,9 +788,9 @@ class JsonCodecMakerSpec extends WordSpec with Matchers {
782788
parsedObj.oc shouldBe defaults.oc
783789
parsedObj.a.deep shouldBe defaults.a.deep
784790
}
785-
"deserialize values of mutable collections in case of null defaults are defined" in {
786-
val json = """{"ml":{"1":1},"mm":{"2":2},"ms":[3],"mb":[4]}""".getBytes
787-
val parsedObj = read(json)(codecOfDefaults)
791+
"deserialize default values in case of missing field or null/empty values" in {
792+
read("""{}""".getBytes)(codecOfDefaults)
793+
read("""{"s":null,"bi":null,"l":[],"oc":null,"a":null}""".getBytes)(codecOfDefaults)
788794
}
789795
"don't serialize and deserialize transient and non constructor defined fields of case classes" in {
790796
verifySerDeser(make[Transient](CodecMakerConfig()), Transient(required = "VVV"), """{"required":"VVV"}""".getBytes)

project/plugins.sbt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@ addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.7")
33
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0-M1")
44
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.3")
55
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1")
6-
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.3.4")
76
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.18")
8-
addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
97
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) // required for circe benchmark

version.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version in ThisBuild := "0.15.1-SNAPSHOT"
1+
version in ThisBuild := "0.16.0-SNAPSHOT"

0 commit comments

Comments
 (0)