tethys-json / tethys

AST free JSON library for Scala
https://tethys-json.github.io/tethys/
Apache License 2.0
110 stars 34 forks source link

Cannot override reader builder of Option field #299

Open anton0xf opened 5 months ago

anton0xf commented 5 months ago

I can read field value from one of two JSON-fields with code like this (and it works well):

import tethys._
import tethys.jackson._
import tethys.derivation.builder._
import tethys.derivation.semiauto._

case class Foo(a: Int)

implicit val fooReader: JsonReader[Foo] = jsonReader[Foo] {
  ReaderBuilder[Foo]
    .extract(_.a)
    .from("a".as[Option[Int]], "b".as[Option[Int]])((a, b) =>
      a.orElse(b)
        .getOrElse(throw new RuntimeException("cannot find 'a' or 'b'"))
    )
}

println("""{"b": 2}""".jsonAs[Foo]) 
// => Right(Foo(2))

Playground

But the same approach doesn't work if a is Option:

// same imports
case class Foo(a: Option[Int])

implicit val fooReader: JsonReader[Foo] = jsonReader[Foo] {
  ReaderBuilder[Foo]
    .extract(_.a)
    .from("a".as[Option[Int]], "b".as[Option[Int]])((a, b) => a.orElse(b))
}

println("""{"b": 2}""".jsonAs[Foo]) 
// => Right(Foo(None)) 
// but expected
// => Right(Foo(2))

Playground

Is it a bug or my misunderstanding?

I tested it on 0.28.3 and some older versions

anton0xf commented 5 months ago

It is even works well if I don't mention "a" fielld:

case class Foo(a: Option[Int])

implicit val fooReader: JsonReader[Foo] = jsonReader[Foo] {
  ReaderBuilder[Foo]
    .extract(_.a)
    .from("c".as[Option[Int]], "b".as[Option[Int]])((c, b) => c.orElse(b))
}

println("""{"b": 2}""".jsonAs[Foo]) // => Right(Foo(Some(2)))
println("""{"c": 2}""".jsonAs[Foo]) // => Right(Foo(Some(2)))

Playground

dos65 commented 5 months ago

Thanks for reporting! That's indeed looks like a bug