circe / circe

Yet another JSON library for Scala

Home Page:https://circe.github.io/circe/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Invalid pathToRoot for `missing required field` validation error

zorba128 opened this issue · comments

Validation error reports invalid path (one segment missing) for missing required field validation error.
See code below to compare how it looks like for invalid field type vs missing field.

  sealed trait A

  case class AA(a: Int) extends A

  case class X(a1: AA, a2: A)

  implicit val aaCodec: Codec[AA] = io.circe.generic.semiauto.deriveCodec
  implicit val aCodec: Codec[A] = io.circe.generic.semiauto.deriveCodec
  implicit val xCodec: Codec[X] = io.circe.generic.semiauto.deriveCodec

  println(X(AA(1), AA(2)).asJson.noSpaces) //{"a1":{"a":1},"a2":{"AA":{"a":2}}}

  // similar input; in first `a1.a` has invalid type, in second `a1.a` is missing
  val input1 = json"""{"a1":{"a":true},"a2":{"AA":{"a":2}}}""" // invalid type
  val input2 = json"""{"a1":{},"a2":{"AA":{"a":2}}}""" // missing required field
  println(input1.as[X]) // Left(DecodingFailure at .a1.a: Int)
  println(input2.as[X]) // Left(DecodingFailure at .a: Missing required field) - path should be as above

  // same here, just with additional nest level
  val input3 = json"""{"a1":{"a":1},"a2":{"AA":{"a":true}}}""" // invalid type
  val input4 = json"""{"a1":{"a":1},"a2":{"AA":{}}}""" // missing required field
  println(input3.as[X]) // Left(DecodingFailure at .a2.AA.a: Int)
  println(input4.as[X]) // Left(DecodingFailure at .a2.a: Missing required field)  - path should be as above

It seems that cursor history in the DecodingFailure is fine, its pathToRoot which is wrong. See another simplified sample below

  @JsonCodec case class Z(z: Int)
  @JsonCodec case class Y(y: Z)
  @JsonCodec case class X(x: Y)

  println(X(Y(Z(1))).asJson.noSpaces) // {"x":{"y":{"z":1}}}
  println(json"""{"x":{"y":{}}}""".as[X]) //Left(DecodingFailure at .x.z: Missing required field)

  // clears pathToRoot using path from cursor history
  def patch[T](a: Either[DecodingFailure, T]) = a.swap.map(a => DecodingFailure(a.reason, a.history)).swap

  println(patch(json"""{"x":{"y":{}}}""".as[X])) //Left(DecodingFailure at .x.y.z: Missing required field)

#2138 I believe fixes this.