Skip to content

Commit 573a334

Browse files
committed
Fix error messages when parsing maps from JSON arrays of JSON arrays + more efficient parsing of maps and sets when limit of inserts is set to infinity
1 parent 48960e7 commit 573a334

File tree

3 files changed

+194
-107
lines changed

3 files changed

+194
-107
lines changed

jsoniter-scala-macros/shared/src/main/scala-2/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMaker.scala

Lines changed: 88 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -977,61 +977,99 @@ object JsonCodecMaker {
977977
} else in.readNullOrTokenError(default, '[')"""
978978

979979
def genReadSet(newBuilder: Tree, readVal: Tree, result: Tree = q"x"): Tree =
980-
q"""if (in.isNextToken('[')) {
981-
if (in.isNextToken(']')) default
982-
else {
983-
in.rollbackToken()
984-
..$newBuilder
985-
var i = 0
986-
while ({
987-
..$readVal
988-
i += 1
989-
if (i > ${cfg.setMaxInsertNumber}) in.decodeError("too many set inserts")
990-
in.isNextToken(',')
991-
}) ()
992-
if (in.isCurrentToken(']')) $result
993-
else in.arrayEndOrCommaError()
994-
}
995-
} else in.readNullOrTokenError(default, '[')"""
980+
if (cfg.setMaxInsertNumber == Int.MaxValue) genReadArray(newBuilder, readVal, result)
981+
else {
982+
q"""if (in.isNextToken('[')) {
983+
if (in.isNextToken(']')) default
984+
else {
985+
in.rollbackToken()
986+
..$newBuilder
987+
var i = 0
988+
while ({
989+
..$readVal
990+
i += 1
991+
if (i > ${cfg.setMaxInsertNumber}) in.decodeError("too many set inserts")
992+
in.isNextToken(',')
993+
}) ()
994+
if (in.isCurrentToken(']')) $result
995+
else in.arrayEndOrCommaError()
996+
}
997+
} else in.readNullOrTokenError(default, '[')"""
998+
}
996999

9971000
def genReadMap(newBuilder: Tree, readKV: Tree, result: Tree = q"x"): Tree =
998-
q"""if (in.isNextToken('{')) {
999-
if (in.isNextToken('}')) default
1000-
else {
1001-
in.rollbackToken()
1002-
..$newBuilder
1003-
var i = 0
1004-
while ({
1005-
..$readKV
1006-
i += 1
1007-
if (i > ${cfg.mapMaxInsertNumber}) in.decodeError("too many map inserts")
1008-
in.isNextToken(',')
1009-
}) ()
1010-
if (in.isCurrentToken('}')) $result
1011-
else in.objectEndOrCommaError()
1012-
}
1013-
} else in.readNullOrTokenError(default, '{')"""
1014-
1015-
def genReadMapAsArray(newBuilder: Tree, readKV: Tree, result: Tree = q"x"): Tree =
1016-
q"""if (in.isNextToken('[')) {
1017-
if (in.isNextToken(']')) default
1018-
else {
1019-
in.rollbackToken()
1020-
..$newBuilder
1021-
var i = 0
1022-
while ({
1023-
if (in.isNextToken('[')) {
1001+
if (cfg.setMaxInsertNumber == Int.MaxValue) {
1002+
q"""if (in.isNextToken('{')) {
1003+
if (in.isNextToken('}')) default
1004+
else {
1005+
in.rollbackToken()
1006+
..$newBuilder
1007+
while ({
1008+
..$readKV
1009+
in.isNextToken(',')
1010+
}) ()
1011+
if (in.isCurrentToken('}')) $result
1012+
else in.objectEndOrCommaError()
1013+
}
1014+
} else in.readNullOrTokenError(default, '{')"""
1015+
} else {
1016+
q"""if (in.isNextToken('{')) {
1017+
if (in.isNextToken('}')) default
1018+
else {
1019+
in.rollbackToken()
1020+
..$newBuilder
1021+
var i = 0
1022+
while ({
10241023
..$readKV
10251024
i += 1
10261025
if (i > ${cfg.mapMaxInsertNumber}) in.decodeError("too many map inserts")
1027-
if (!in.isNextToken(']')) in.arrayEndError()
1028-
} else in.readNullOrTokenError(default, '[')
1029-
in.isNextToken(',')
1030-
}) ()
1031-
if (in.isCurrentToken(']')) $result
1032-
else in.objectEndOrCommaError()
1033-
}
1034-
} else in.readNullOrTokenError(default, '[')"""
1026+
in.isNextToken(',')
1027+
}) ()
1028+
if (in.isCurrentToken('}')) $result
1029+
else in.objectEndOrCommaError()
1030+
}
1031+
} else in.readNullOrTokenError(default, '{')"""
1032+
}
1033+
1034+
def genReadMapAsArray(newBuilder: Tree, readKV: Tree, result: Tree = q"x"): Tree =
1035+
if (cfg.setMaxInsertNumber == Int.MaxValue) {
1036+
q"""if (in.isNextToken('[')) {
1037+
if (in.isNextToken(']')) default
1038+
else {
1039+
in.rollbackToken()
1040+
..$newBuilder
1041+
while ({
1042+
if (in.isNextToken('[')) {
1043+
..$readKV
1044+
if (!in.isNextToken(']')) in.arrayEndError()
1045+
} else in.decodeError("expected '['")
1046+
in.isNextToken(',')
1047+
}) ()
1048+
if (in.isCurrentToken(']')) $result
1049+
else in.arrayEndOrCommaError()
1050+
}
1051+
} else in.readNullOrTokenError(default, '[')"""
1052+
} else {
1053+
q"""if (in.isNextToken('[')) {
1054+
if (in.isNextToken(']')) default
1055+
else {
1056+
in.rollbackToken()
1057+
..$newBuilder
1058+
var i = 0
1059+
while ({
1060+
if (in.isNextToken('[')) {
1061+
..$readKV
1062+
i += 1
1063+
if (i > ${cfg.mapMaxInsertNumber}) in.decodeError("too many map inserts")
1064+
if (!in.isNextToken(']')) in.arrayEndError()
1065+
} else in.decodeError("expected '['")
1066+
in.isNextToken(',')
1067+
}) ()
1068+
if (in.isCurrentToken(']')) $result
1069+
else in.arrayEndOrCommaError()
1070+
}
1071+
} else in.readNullOrTokenError(default, '[')"""
1072+
}
10351073

10361074
@tailrec
10371075
def genWriteKey(x: Tree, types: List[Type]): Tree = {

jsoniter-scala-macros/shared/src/main/scala-3/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMaker.scala

Lines changed: 92 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,69 +1260,104 @@ object JsonCodecMaker {
12601260
}
12611261

12621262
def genReadSet[B: Type, C: Type](newBuilder: Expr[B], readVal: Quotes ?=> Expr[B] => Expr[Unit], default: Expr[C],
1263-
result: Quotes ?=> Expr[B] => Expr[C], in: Expr[JsonReader])(using Quotes): Expr[C] = '{
1264-
if ($in.isNextToken('[')) {
1265-
if ($in.isNextToken(']')) $default
1266-
else {
1267-
$in.rollbackToken()
1268-
var x = $newBuilder
1269-
var i = 0
1270-
while ({
1271-
${readVal('x)}
1272-
i += 1
1273-
if (i > ${Expr(cfg.setMaxInsertNumber)}) $in.decodeError("too many set inserts")
1274-
$in.isNextToken(',')
1275-
}) ()
1276-
if ($in.isCurrentToken(']')) ${result('x)}
1277-
else $in.arrayEndOrCommaError()
1278-
}
1279-
} else $in.readNullOrTokenError($default, '[')
1280-
}
1263+
result: Quotes ?=> Expr[B] => Expr[C], in: Expr[JsonReader])(using Quotes): Expr[C] =
1264+
if (cfg.setMaxInsertNumber == Int.MaxValue) genReadCollection(newBuilder, readVal, default, result, in)
1265+
else '{
1266+
if ($in.isNextToken('[')) {
1267+
if ($in.isNextToken(']')) $default
1268+
else {
1269+
$in.rollbackToken()
1270+
var x = $newBuilder
1271+
var i = 0
1272+
while ({
1273+
${readVal('x)}
1274+
i += 1
1275+
if (i > ${Expr(cfg.setMaxInsertNumber)}) $in.decodeError("too many set inserts")
1276+
$in.isNextToken(',')
1277+
}) ()
1278+
if ($in.isCurrentToken(']')) ${result('x)}
1279+
else $in.arrayEndOrCommaError()
1280+
}
1281+
} else $in.readNullOrTokenError($default, '[')
1282+
}
12811283

12821284
def genReadMap[B: Type, C: Type](newBuilder: Expr[B], readKV: Quotes ?=> Expr[B] => Expr[Unit],
12831285
result: Quotes ?=> Expr[B]=>Expr[C], in: Expr[JsonReader],
1284-
default: Expr[C])(using Quotes): Expr[C] = '{
1285-
if ($in.isNextToken('{')) {
1286-
if ($in.isNextToken('}')) $default
1287-
else {
1288-
$in.rollbackToken()
1289-
var x = $newBuilder
1290-
var i = 0
1291-
while ({
1292-
${readKV('x)}
1293-
i += 1
1294-
if (i > ${Expr(cfg.mapMaxInsertNumber)}) $in.decodeError("too many map inserts")
1295-
$in.isNextToken(',')
1296-
}) ()
1297-
if ($in.isCurrentToken('}')) ${result('x)}
1298-
else $in.objectEndOrCommaError()
1299-
}
1300-
} else $in.readNullOrTokenError($default, '{')
1301-
}
1302-
1303-
def genReadMapAsArray[B: Type, C: Type](newBuilder: Expr[B], readKV: Quotes ?=> Expr[B] => Expr[Unit],
1304-
result: Quotes ?=> Expr[B] => Expr[C], in: Expr[JsonReader],
1305-
default: Expr[C])(using Quotes): Expr[C] = '{
1306-
if ($in.isNextToken('[')) {
1307-
if ($in.isNextToken(']')) $default
1308-
else {
1309-
$in.rollbackToken()
1310-
var x = $newBuilder
1311-
var i = 0
1312-
while ({
1313-
if ($in.isNextToken('[')) {
1286+
default: Expr[C])(using Quotes): Expr[C] =
1287+
if (cfg.setMaxInsertNumber == Int.MaxValue) '{
1288+
if ($in.isNextToken('{')) {
1289+
if ($in.isNextToken('}')) $default
1290+
else {
1291+
$in.rollbackToken()
1292+
var x = $newBuilder
1293+
while ({
1294+
${readKV('x)}
1295+
$in.isNextToken(',')
1296+
}) ()
1297+
if ($in.isCurrentToken('}')) ${result('x)}
1298+
else $in.objectEndOrCommaError()
1299+
}
1300+
} else $in.readNullOrTokenError($default, '{')
1301+
} else '{
1302+
if ($in.isNextToken('{')) {
1303+
if ($in.isNextToken('}')) $default
1304+
else {
1305+
$in.rollbackToken()
1306+
var x = $newBuilder
1307+
var i = 0
1308+
while ({
13141309
${readKV('x)}
13151310
i += 1
13161311
if (i > ${Expr(cfg.mapMaxInsertNumber)}) $in.decodeError("too many map inserts")
1317-
if (!$in.isNextToken(']')) $in.arrayEndError()
1318-
} else $in.readNullOrTokenError($default, '[')
1319-
$in.isNextToken(',')
1320-
}) ()
1321-
if ($in.isCurrentToken(']')) ${result('x)}
1322-
else $in.objectEndOrCommaError()
1323-
}
1324-
} else $in.readNullOrTokenError($default, '[')
1325-
}
1312+
$in.isNextToken(',')
1313+
}) ()
1314+
if ($in.isCurrentToken('}')) ${result('x)}
1315+
else $in.objectEndOrCommaError()
1316+
}
1317+
} else $in.readNullOrTokenError($default, '{')
1318+
}
1319+
1320+
def genReadMapAsArray[B: Type, C: Type](newBuilder: Expr[B], readKV: Quotes ?=> Expr[B] => Expr[Unit],
1321+
result: Quotes ?=> Expr[B] => Expr[C], in: Expr[JsonReader],
1322+
default: Expr[C])(using Quotes): Expr[C] =
1323+
if (cfg.setMaxInsertNumber == Int.MaxValue) '{
1324+
if ($in.isNextToken('[')) {
1325+
if ($in.isNextToken(']')) $default
1326+
else {
1327+
$in.rollbackToken()
1328+
var x = $newBuilder
1329+
while ({
1330+
if ($in.isNextToken('[')) {
1331+
${readKV('x)}
1332+
if (!$in.isNextToken(']')) $in.arrayEndError()
1333+
} else $in.decodeError("expected '['")
1334+
$in.isNextToken(',')
1335+
}) ()
1336+
if ($in.isCurrentToken(']')) ${result('x)}
1337+
else $in.arrayEndOrCommaError()
1338+
}
1339+
} else $in.readNullOrTokenError($default, '[')
1340+
} else '{
1341+
if ($in.isNextToken('[')) {
1342+
if ($in.isNextToken(']')) $default
1343+
else {
1344+
$in.rollbackToken()
1345+
var x = $newBuilder
1346+
var i = 0
1347+
while ({
1348+
if ($in.isNextToken('[')) {
1349+
${readKV('x)}
1350+
i += 1
1351+
if (i > ${Expr(cfg.mapMaxInsertNumber)}) $in.decodeError("too many map inserts")
1352+
if (!$in.isNextToken(']')) $in.arrayEndError()
1353+
} else $in.decodeError("expected '['")
1354+
$in.isNextToken(',')
1355+
}) ()
1356+
if ($in.isCurrentToken(']')) ${result('x)}
1357+
else $in.arrayEndOrCommaError()
1358+
}
1359+
} else $in.readNullOrTokenError($default, '[')
1360+
}
13261361

13271362
@tailrec
13281363
def genWriteKey[T: Type](x: Expr[T], types: List[TypeRepr], out: Expr[JsonWriter])(using Quotes): Expr[Unit] =

jsoniter-scala-macros/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMakerSpec.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,20 @@ class JsonCodecMakerSpec extends VerifyingSpec {
16931693
verifyDeserError(codecOfImmutableMaps, """{"m":{"1":1.1,},"hm":{},"sm":{}""",
16941694
"""expected '"', offset: 0x0000000e""")
16951695
}
1696+
"throw parse exception in case of JSON array of JSON arrays is not properly started/closed or with leading/trailing comma" in {
1697+
val codecOfMapAsArray = make[_root_.scala.collection.Map[Int, _root_.scala.Boolean]](CodecMakerConfig.withMapAsArray(true))
1698+
verifyDeserError(codecOfMapAsArray, """{[1,true]]""", """expected '[' or null, offset: 0x00000000""")
1699+
verifyDeserError(codecOfMapAsArray, """[,[1,true]]""", """expected '[', offset: 0x00000001""")
1700+
verifyDeserError(codecOfMapAsArray, """[[1,true,]]""", """expected ']', offset: 0x00000008""")
1701+
verifyDeserError(codecOfMapAsArray, """[[1,true]}""", """expected ']' or ',', offset: 0x00000009""")
1702+
verifyDeserError(codecOfMapAsArray, """[[1,true],]""", """expected '[', offset: 0x0000000a""")
1703+
val codecOfMapAsArray2 = make[_root_.scala.collection.Map[Int, _root_.scala.Boolean]](CodecMakerConfig.withMapAsArray(true).withMapMaxInsertNumber(Int.MaxValue))
1704+
verifyDeserError(codecOfMapAsArray2, """{[1,true]]""", """expected '[' or null, offset: 0x00000000""")
1705+
verifyDeserError(codecOfMapAsArray2, """[,[1,true]]""", """expected '[', offset: 0x00000001""")
1706+
verifyDeserError(codecOfMapAsArray2, """[[1,true,]]""", """expected ']', offset: 0x00000008""")
1707+
verifyDeserError(codecOfMapAsArray2, """[[1,true]}""", """expected ']' or ',', offset: 0x00000009""")
1708+
verifyDeserError(codecOfMapAsArray2, """[[1,true],]""", """expected '[', offset: 0x0000000a""")
1709+
}
16961710
"throw parse exception in case of illegal keys found during deserialization of maps" in {
16971711
verifyDeserError(codecOfMutableMaps, """{"m":{"1.1":{"null":"2"}}""", "illegal number, offset: 0x0000000e")
16981712
}

0 commit comments

Comments
 (0)