amnaredo / test

0 stars 0 forks source link

Null JSON values with AnyVal fields produces NPE #208

Open amnaredo opened 3 years ago

amnaredo commented 3 years ago

Null values in JSON produce an NPE if we attempt to unpickle into a field with an AnyVal type. The following two tests are the same except Foo extends AnyVal in the first one:

object AnyValTest {

  final case class Foo(a: String) extends AnyVal

  implicit val fooReader = upickle.default.Reader[Foo] {
    case upickle.Js.Str(s) => Foo(s)
  }

  final case class Bar(foo: Foo)

  def fails = upickle.default.read[Bar]("""
    { "foo": null }
  """)

  def works = upickle.default.read[Bar]("""
    { "foo": "x" }
  """)

}

object AnyRefTest {

  final case class Foo(a: String)

  implicit val fooReader = upickle.default.Reader[Foo] {
    case upickle.Js.Str(s) => Foo(s)
  }

  final case class Bar(foo: Foo)

  def works = upickle.default.read[Bar]("""
    { "foo": null }
  """)

}

AnyValTest.works and AnyRefTest.works produce the expected results, but AnyValTest.fails gives:

java.lang.NullPointerException
  $sess.cmd34$AnyValTest$$anon$1.$anonfun$derive$macro$416$2(cmd34.sc:11)
  upickle.Implicits$$anonfun$CaseR$1.applyOrElse(Implicits.scala:120)
  upickle.Implicits$$anonfun$CaseR$1.applyOrElse(Implicits.scala:119)
  upickle.Types$Reader$$anon$2.apply(Types.scala:113)
  upickle.Types$Reader$$anon$2.apply(Types.scala:103)
  scala.PartialFunction.applyOrElse(PartialFunction.scala:123)
  scala.PartialFunction.applyOrElse$(PartialFunction.scala:122)
  upickle.Types$Reader$$anon$2.applyOrElse(Types.scala:103)
  upickle.Implicits$Internal$$anon$1.apply(Implicits.scala:83)
  upickle.Implicits$Internal$$anon$1.apply(Implicits.scala:80)
  scala.PartialFunction.applyOrElse(PartialFunction.scala:123)
  scala.PartialFunction.applyOrElse$(PartialFunction.scala:122)
  upickle.Implicits$Internal$$anon$1.applyOrElse(Implicits.scala:80)
  upickle.Types$Reader$$anon$2.apply(Types.scala:113)
  upickle.Types$Reader$$anon$2.apply(Types.scala:103)
  upickle.Types.readJs(Types.scala:160)
  upickle.Types.readJs$(Types.scala:160)
  upickle.default$.readJs(Api.scala:25)
  upickle.Types.read(Types.scala:156)
  upickle.Types.read$(Types.scala:156)
  upickle.default$.read(Api.scala:25)
  $sess.cmd34$AnyValTest$.fails(cmd34.sc:11)
  $sess.cmd36$.<init>(cmd36.sc:1)
  $sess.cmd36$.<clinit>(cmd36.sc:-1)

It seems to be the case that AnyVal references can't be null (weirdly it does work if you coerce to make the compiler happy: Bar(null.asInstanceOf[Foo])). So it's likely that this should not work, but it would be great if upickle could detect this case and give a better error. It took me a long time to figure out that the attempted null AnyVal was the issue.

ID: 202 Original Author: quelgar

amnaredo commented 3 years ago

Bug bankruptcy Original Author: lihaoyi