使用 circe 在类主体中使用“require”解码案例类会引发异常,而不是返回“Left”

iDP*_*WF1 1 json scala circe

我有一个案例类,其中一些逻辑约束require在案例类主体中作为 s 实现。当尝试从表示语法正确但逻辑上无效的实例的 JSON 中解码此案例类时,异常实际上是在调用线程上引发的,而不是作为Leftfrom的返回decode

重现代码片段:

case class Foo(bar: String) {
  require(bar.length < 5)
}

object Sandbox extends App {
  import io.circe.generic.auto._
  import io.circe.parser._

  val foo1 = decode[Foo](""" {"bar":"abc"} """)
  println(s"foo1: $foo1")

  //expected: Left(IllegalArgumentException("requirement failed"))
  //actual: throws IllegalArgumentException("requirement failed")
  val foo2 = decode[Foo](""" {"bar":"abcdefg"} """) 
  println(s"foo2: $foo2")
}
Run Code Online (Sandbox Code Playgroud)

是否可以让此异常返回而不Left抛出decode?欢迎任何想法/建议...

TIA

M。

Mat*_*zok 5

使用精炼在有约束的情况下自动派生这些编解码器。

或者,如果您想验证 JSON 但不验证构造函数,您可以随时调整编解码器,例如

case class Foo(bar: String)
object Foo {
  implicit val decoder: Decoder[Foo] = deriveDecoder[Foo].emapTry(foo =>
    Try(require(foo.bar.length < 5))
  )
}
Run Code Online (Sandbox Code Playgroud)

有时您还可以使用中间类型进行推导并映射它:

case class Foo(bar: String) {
  require(bar.length < 5)
}
object Foo {
  // allows usage of derivation, especially if you would derive several typeclasses
  // and then adjust their behavior
  private case class FooHelper(bar: String)

  implicit val decoder: Decoder[Foo] = deriveDecoder[FooHelper].emapTry(helper =>
    Try(Foo(helper.foo))
  )
}
Run Code Online (Sandbox Code Playgroud)

一般来说,我建议不要使用require,特别是在构造函数中,而使用智能构造函数。

sealed abstract case class Foo private (bar: String)
object Foo {

  def parse(bar: String): Either[String, Foo] =
    if (bar.length < 5) Right(new Foo(bar) {})
    else Left(s"Invalid bar value: $bar")

  def parseUnsafe(bar: String): Foo =
   parse(bar).fold(error => throw new Exception(error), foo => foo)

  private case class FooHelper(bar: String)

  implicit val decoder: Decoder[Foo] = deriveDecoder[FooHelper].emapTry(helper =>
    Try(parseUsafe(helper.foo))
  )
}
Run Code Online (Sandbox Code Playgroud)