Skip to content

Commit ed64541

Browse files
committed
fix: Add throw error on jsonCodec decoder on JSON string with extra char
1 parent 5a276f7 commit ed64541

File tree

2 files changed

+160
-93
lines changed

2 files changed

+160
-93
lines changed

zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala

Lines changed: 120 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,25 @@ object JsonCodec {
489489
import Codecs._
490490
import ProductDecoder._
491491

492-
final def decode[A](schema: Schema[A], json: String): Either[DecodeError, A] =
493-
schemaDecoder(schema).decodeJson(json) match {
492+
final def decode[A](schema: Schema[A], json: String): Either[DecodeError, A] = {
493+
val trimmedJson = json.trim
494+
schemaDecoder(schema).decodeJson(trimmedJson) match {
494495
case Left(value) => Left(ReadError(Cause.empty, value))
495-
case Right(value) => Right(value)
496+
case Right(value) =>
497+
// Check for any remaining non-whitespace characters
498+
val lastValidChar = trimmedJson.last match {
499+
case '}' => trimmedJson.lastIndexOf('}')
500+
case ']' => trimmedJson.lastIndexOf(']')
501+
case '"' => trimmedJson.lastIndexOf('"')
502+
case _ => trimmedJson.length - 1
503+
}
504+
if (trimmedJson.length > lastValidChar + 1) {
505+
Left(ReadError(Cause.empty, "Unexpected characters after end of JSON"))
506+
} else {
507+
Right(value)
508+
}
496509
}
510+
}
497511

498512
def x[A](dec: ZJsonDecoder[A]): Unit = dec match {
499513
case _: ZJsonDecoder[_] =>
@@ -543,96 +557,109 @@ object JsonCodec {
543557
}
544558

545559
//scalafmt: { maxColumn = 400, optIn.configStyleArguments = false }
546-
private[codec] def schemaDecoder[A](schema: Schema[A], discriminator: Int = -1): ZJsonDecoder[A] = schema match {
547-
case Schema.Primitive(standardType, _) => primitiveCodec(standardType).decoder
548-
case Schema.Optional(codec, _) => option(schemaDecoder(codec, discriminator))
549-
case Schema.Tuple2(left, right, _) => ZJsonDecoder.tuple2(schemaDecoder(left, -1), schemaDecoder(right, -1))
550-
case Schema.Transform(c, f, _, a, _) => schemaDecoder(a.foldLeft(c)((s, a) => s.annotate(a)), discriminator).mapOrFail(f)
551-
case Schema.Sequence(codec, f, _, _, _) => ZJsonDecoder.chunk(schemaDecoder(codec, -1)).map(f)
552-
case Schema.Map(ks, vs, _) => mapDecoder(ks, vs)
553-
case Schema.Set(s, _) => ZJsonDecoder.chunk(schemaDecoder(s, -1)).map(entries => entries.toSet)
554-
case Schema.Fail(message, _) => failDecoder(message)
555-
case Schema.GenericRecord(_, structure, _) => recordDecoder(structure.toChunk, schema.annotations.contains(rejectExtraFields()))
556-
case Schema.Either(left, right, _) => ZJsonDecoder.either(schemaDecoder(left, -1), schemaDecoder(right, -1))
557-
case s @ Schema.Fallback(_, _, _, _) => fallbackDecoder(s)
558-
case l @ Schema.Lazy(_) => schemaDecoder(l.schema, discriminator)
559-
//case Schema.Meta(_, _) => astDecoder
560-
case s @ Schema.CaseClass0(_, _, _) => caseClass0Decoder(discriminator, s)
561-
case s @ Schema.CaseClass1(_, _, _, _) => caseClass1Decoder(discriminator, s)
562-
case s @ Schema.CaseClass2(_, _, _, _, _) => caseClass2Decoder(discriminator, s)
563-
case s @ Schema.CaseClass3(_, _, _, _, _, _) => caseClass3Decoder(discriminator, s)
564-
case s @ Schema.CaseClass4(_, _, _, _, _, _, _) => caseClass4Decoder(discriminator, s)
565-
case s @ Schema.CaseClass5(_, _, _, _, _, _, _, _) => caseClass5Decoder(discriminator, s)
566-
case s @ Schema.CaseClass6(_, _, _, _, _, _, _, _, _) => caseClass6Decoder(discriminator, s)
567-
case s @ Schema.CaseClass7(_, _, _, _, _, _, _, _, _, _) => caseClass7Decoder(discriminator, s)
568-
case s @ Schema.CaseClass8(_, _, _, _, _, _, _, _, _, _, _) => caseClass8Decoder(discriminator, s)
569-
case s @ Schema.CaseClass9(_, _, _, _, _, _, _, _, _, _, _, _) => caseClass9Decoder(discriminator, s)
570-
case s @ Schema.CaseClass10(_, _, _, _, _, _, _, _, _, _, _, _, _) => caseClass10Decoder(discriminator, s)
571-
case s @ Schema.CaseClass11(_, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
572-
caseClass11Decoder(discriminator, s)
573-
case s @ Schema.CaseClass12(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
574-
caseClass12Decoder(discriminator, s)
575-
case s @ Schema.CaseClass13(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
576-
caseClass13Decoder(discriminator, s)
577-
case s @ Schema
578-
.CaseClass14(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
579-
caseClass14Decoder(discriminator, s)
580-
case s @ Schema
581-
.CaseClass15(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
582-
caseClass15Decoder(discriminator, s)
583-
case s @ Schema.CaseClass16(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
584-
caseClass16Decoder(discriminator, s)
585-
case s @ Schema.CaseClass17(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
586-
caseClass17Decoder(discriminator, s)
587-
case s @ Schema.CaseClass18(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
588-
caseClass18Decoder(discriminator, s)
589-
case s @ Schema.CaseClass19(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
590-
caseClass19Decoder(discriminator, s)
591-
case s @ Schema.CaseClass20(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
592-
caseClass20Decoder(discriminator, s)
593-
case s @ Schema.CaseClass21(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
594-
caseClass21Decoder(discriminator, s)
595-
case s @ Schema.CaseClass22(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
596-
caseClass22Decoder(discriminator, s)
597-
case e @ Schema.Enum1(_, c, _) => enumDecoder(e, c)
598-
case e @ Schema.Enum2(_, c1, c2, _) => enumDecoder(e, c1, c2)
599-
case e @ Schema.Enum3(_, c1, c2, c3, _) => enumDecoder(e, c1, c2, c3)
600-
case e @ Schema.Enum4(_, c1, c2, c3, c4, _) => enumDecoder(e, c1, c2, c3, c4)
601-
case e @ Schema.Enum5(_, c1, c2, c3, c4, c5, _) => enumDecoder(e, c1, c2, c3, c4, c5)
602-
case e @ Schema.Enum6(_, c1, c2, c3, c4, c5, c6, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6)
603-
case e @ Schema.Enum7(_, c1, c2, c3, c4, c5, c6, c7, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6, c7)
604-
case e @ Schema.Enum8(_, c1, c2, c3, c4, c5, c6, c7, c8, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8)
605-
case e @ Schema.Enum9(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9)
606-
case e @ Schema.Enum10(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, _) =>
607-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10)
608-
case e @ Schema.Enum11(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, _) =>
609-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)
610-
case e @ Schema.Enum12(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, _) =>
611-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)
612-
case e @ Schema.Enum13(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, _) =>
613-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
614-
case e @ Schema.Enum14(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, _) =>
615-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14)
616-
case e @ Schema.Enum15(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, _) =>
617-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15)
618-
case e @ Schema.Enum16(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, _) =>
619-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16)
620-
case e @ Schema.Enum17(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, _) =>
621-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17)
622-
case e @ Schema.Enum18(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, _) =>
623-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18)
624-
case e @ Schema.Enum19(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, _) =>
625-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19)
626-
case e @ Schema
627-
.Enum20(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, _) =>
628-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20)
629-
case e @ Schema.Enum21(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, _) =>
630-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21)
631-
case e @ Schema.Enum22(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, _) =>
632-
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22)
633-
case e @ Schema.EnumN(_, cs, _) => enumDecoder(e, cs.toSeq: _*)
634-
case d @ Schema.Dynamic(_) => dynamicDecoder(d)
635-
case _ => throw new Exception(s"Missing a handler for decoding of schema ${schema.toString()}.")
560+
private[codec] def schemaDecoder[A](schema: Schema[A], discriminator: Int = -1): ZJsonDecoder[A] = {
561+
new ZJsonDecoder[A] {
562+
def unsafeDecode(trace: List[JsonError], in: RetractReader): A = {
563+
val result = schema match {
564+
case Schema.Primitive(standardType, _) => primitiveCodec(standardType).decoder
565+
case Schema.Optional(codec, _) => option(schemaDecoder(codec, discriminator))
566+
case Schema.Tuple2(left, right, _) => ZJsonDecoder.tuple2(schemaDecoder(left, -1), schemaDecoder(right, -1))
567+
case Schema.Transform(c, f, _, a, _) => schemaDecoder(a.foldLeft(c)((s, a) => s.annotate(a)), discriminator).mapOrFail(f)
568+
case Schema.Sequence(codec, f, _, _, _) => ZJsonDecoder.chunk(schemaDecoder(codec, -1)).map(f)
569+
case Schema.Map(ks, vs, _) => mapDecoder(ks, vs)
570+
case Schema.Set(s, _) => ZJsonDecoder.chunk(schemaDecoder(s, -1)).map(entries => entries.toSet)
571+
case Schema.Fail(message, _) => failDecoder(message)
572+
case Schema.GenericRecord(_, structure, _) => recordDecoder(structure.toChunk, schema.annotations.contains(rejectExtraFields()))
573+
case Schema.Either(left, right, _) => ZJsonDecoder.either(schemaDecoder(left, -1), schemaDecoder(right, -1))
574+
case s @ Schema.Fallback(_, _, _, _) => fallbackDecoder(s)
575+
case l @ Schema.Lazy(_) => schemaDecoder(l.schema, discriminator)
576+
//case Schema.Meta(_, _) => astDecoder
577+
case s @ Schema.CaseClass0(_, _, _) => caseClass0Decoder(discriminator, s)
578+
case s @ Schema.CaseClass1(_, _, _, _) => caseClass1Decoder(discriminator, s)
579+
case s @ Schema.CaseClass2(_, _, _, _, _) => caseClass2Decoder(discriminator, s)
580+
case s @ Schema.CaseClass3(_, _, _, _, _, _) => caseClass3Decoder(discriminator, s)
581+
case s @ Schema.CaseClass4(_, _, _, _, _, _, _) => caseClass4Decoder(discriminator, s)
582+
case s @ Schema.CaseClass5(_, _, _, _, _, _, _, _) => caseClass5Decoder(discriminator, s)
583+
case s @ Schema.CaseClass6(_, _, _, _, _, _, _, _, _) => caseClass6Decoder(discriminator, s)
584+
case s @ Schema.CaseClass7(_, _, _, _, _, _, _, _, _, _) => caseClass7Decoder(discriminator, s)
585+
case s @ Schema.CaseClass8(_, _, _, _, _, _, _, _, _, _, _) => caseClass8Decoder(discriminator, s)
586+
case s @ Schema.CaseClass9(_, _, _, _, _, _, _, _, _, _, _, _) => caseClass9Decoder(discriminator, s)
587+
case s @ Schema.CaseClass10(_, _, _, _, _, _, _, _, _, _, _, _, _) => caseClass10Decoder(discriminator, s)
588+
case s @ Schema.CaseClass11(_, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
589+
caseClass11Decoder(discriminator, s)
590+
case s @ Schema.CaseClass12(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
591+
caseClass12Decoder(discriminator, s)
592+
case s @ Schema.CaseClass13(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
593+
caseClass13Decoder(discriminator, s)
594+
case s @ Schema
595+
.CaseClass14(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
596+
caseClass14Decoder(discriminator, s)
597+
case s @ Schema
598+
.CaseClass15(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
599+
caseClass15Decoder(discriminator, s)
600+
case s @ Schema.CaseClass16(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
601+
caseClass16Decoder(discriminator, s)
602+
case s @ Schema.CaseClass17(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
603+
caseClass17Decoder(discriminator, s)
604+
case s @ Schema.CaseClass18(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
605+
caseClass18Decoder(discriminator, s)
606+
case s @ Schema.CaseClass19(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
607+
caseClass19Decoder(discriminator, s)
608+
case s @ Schema.CaseClass20(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
609+
caseClass20Decoder(discriminator, s)
610+
case s @ Schema.CaseClass21(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
611+
caseClass21Decoder(discriminator, s)
612+
case s @ Schema.CaseClass22(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) =>
613+
caseClass22Decoder(discriminator, s)
614+
case e @ Schema.Enum1(_, c, _) => enumDecoder(e, c)
615+
case e @ Schema.Enum2(_, c1, c2, _) => enumDecoder(e, c1, c2)
616+
case e @ Schema.Enum3(_, c1, c2, c3, _) => enumDecoder(e, c1, c2, c3)
617+
case e @ Schema.Enum4(_, c1, c2, c3, c4, _) => enumDecoder(e, c1, c2, c3, c4)
618+
case e @ Schema.Enum5(_, c1, c2, c3, c4, c5, _) => enumDecoder(e, c1, c2, c3, c4, c5)
619+
case e @ Schema.Enum6(_, c1, c2, c3, c4, c5, c6, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6)
620+
case e @ Schema.Enum7(_, c1, c2, c3, c4, c5, c6, c7, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6, c7)
621+
case e @ Schema.Enum8(_, c1, c2, c3, c4, c5, c6, c7, c8, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8)
622+
case e @ Schema.Enum9(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, _) => enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9)
623+
case e @ Schema.Enum10(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, _) =>
624+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10)
625+
case e @ Schema.Enum11(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, _) =>
626+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)
627+
case e @ Schema.Enum12(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, _) =>
628+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)
629+
case e @ Schema.Enum13(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, _) =>
630+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
631+
case e @ Schema.Enum14(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, _) =>
632+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14)
633+
case e @ Schema.Enum15(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, _) =>
634+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15)
635+
case e @ Schema.Enum16(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, _) =>
636+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16)
637+
case e @ Schema.Enum17(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, _) =>
638+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17)
639+
case e @ Schema.Enum18(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, _) =>
640+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18)
641+
case e @ Schema.Enum19(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, _) =>
642+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19)
643+
case e @ Schema
644+
.Enum20(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, _) =>
645+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20)
646+
case e @ Schema.Enum21(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, _) =>
647+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21)
648+
case e @ Schema.Enum22(_, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, _) =>
649+
enumDecoder(e, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22)
650+
case e @ Schema.EnumN(_, cs, _) => enumDecoder(e, cs.toSeq: _*)
651+
case d @ Schema.Dynamic(_) => dynamicDecoder(d)
652+
case _ => throw new Exception(s"Missing a handler for decoding of schema ${schema.toString()}.")
653+
}
654+
655+
// Check for unexpected characters after parsing
656+
if (in.nextNonWhitespace() != -1) {
657+
throw UnsafeJson(JsonError.Message("Unexpected characters after parsed content") :: trace)
658+
}
659+
660+
result.asInstanceOf[A]
661+
}
662+
}
636663
}
637664
//scalafmt: { maxColumn = 120, optIn.configStyleArguments = true }
638665

zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ import zio.test._
2424

2525
object JsonCodecSpec extends ZIOSpecDefault {
2626

27+
object Foo {
28+
implicit val schema: Schema[Foo.type] = DeriveSchema.gen[Foo.type]
29+
}
30+
31+
final case class Bar(a: Int)
32+
33+
object Bar {
34+
implicit val schema: Schema[Bar] = DeriveSchema.gen[Bar]
35+
}
36+
2737
def spec: Spec[TestEnvironment, Any] =
2838
suite("JsonCodec Spec")(
2939
encoderSuite,
@@ -884,6 +894,36 @@ object JsonCodecSpec extends ZIOSpecDefault {
884894
charSequenceToByteChunk("""null""")
885895
)
886896
}
897+
),
898+
suite("zio.schema.codec.JsonCodec.jsonDecoder reject extra characters")(
899+
test("extra } in empty object") {
900+
assertTrue(
901+
zio.schema.codec.JsonCodec
902+
.jsonDecoder(Schema[Foo.type])
903+
.decodeJson(
904+
"""{}}"""
905+
)
906+
.isLeft
907+
)
908+
},
909+
test("extra } in non-empty object") {
910+
assertTrue(
911+
zio.schema.codec.JsonCodec
912+
.jsonDecoder(Schema[Bar])
913+
.decodeJson(
914+
"""{"a":1}}"""
915+
)
916+
.isLeft
917+
)
918+
},
919+
test("extra \" in string") {
920+
assertTrue(
921+
zio.schema.codec.JsonCodec
922+
.jsonDecoder(Schema[String])
923+
.decodeJson("\"foo\"\"")
924+
.isLeft
925+
)
926+
}
887927
)
888928
)
889929

0 commit comments

Comments
 (0)