spray-json parseJson 函数的故障安全包装器

Fail-safe wrapper for spary-json parseJson func

我想为 spary-jsonstr.parseJson.convertTo[A] 编写故障安全包装器。 它必须有逻辑 - "when I can't parse json as case class A, I try parse it as case class Error"

def parse(str:String) = 
   try {
     str.parseJson.convertTo[A]
   } catch {
     case e:Exception => str.parseJson.convertTo[Error]
   }

但我也想将 class A 作为参数。

def parse[A<:Obj](str:String):Obj = {
  import JsonProtocols._
  try {
    str.parseJson.convertTo[A]
  } catch {
    case e:Exception => str.parseJson.convertTo[Error]
  }
}

使用:

...
trait Obj

case class Error(error:String) extends Obj
case class DataA(a1:String, a2: Int) extends Obj
case class DataB(b1:String, b2: Boolean) extends Obj
object JsonProtocols extends DefaultJsonProtocol {
  implicit val errorFormat = jsonFormat1(Error)
  implicit val dataAFormat = jsonFormat2(DataA)
  implicit val dataBFormat = jsonFormat2(DataB)
  ...
}

...
parse[DataA]("...json...") match {
  case obj: DataA => "..."
  case obj: Error => "..."
}
...

我遇到编译错误:

Error:(25, 30) Cannot find JsonReader or JsonFormat type class for A
      str.parseJson.convertTo[A]

                         ^

我该如何解决这个错误? 我可以用其他方式做到这一点吗?

简化事情,看起来你已经:

  • 使用适当的 JsonReaders
  • 定义了 3 个案例 类
  • 定义了一个泛型函数,其类型 lower 绑定到 Obj。

编译器告诉您它无法为 all possible 类 implementing trait Obj 找到 JsonReader,因为您只为 Error 定义了特定的 JsonReader , DataA 和 DataB.

要解决此问题,您可以使用 Either[T,Error] 类型进行反序列化,例如:

  sealed trait Obj
  case class Error(error:String) extends Obj
  case class DataA(a1:String, a2: Int) extends Obj
  case class DataB(b1:String, b2: Boolean) extends Obj

  val strA = """{"a1":"foo", "a2": 1}"""
  val strB = """{"b1":"bar", "b2": false}"""
  val srtE = """{"error": "oops"}"""

  object JsonProtocols extends DefaultJsonProtocol {
    implicit val errorFormat = jsonFormat1(Error)
    implicit val dataAFormat = jsonFormat2(DataA)
    implicit val dataBFormat = jsonFormat2(DataB)
  }

  import JsonProtocols._
  val result:Obj = strA.parseJson.convertTo[Either[DataA,Error]] match {
    case Left(dataA) => dataA
    case Right(error) => error
  }