I want to write fail-safe wrapper for spary-json str.parseJson.convertTo[A]
.
It must have logic - "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]
}
but also I want to make class A
a parameter.
def parse[A<:Obj](str:String):Obj = {
import JsonProtocols._
try {
str.parseJson.convertTo[A]
} catch {
case e:Exception => str.parseJson.convertTo[Error]
}
}
using:
...
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 => "..."
}
...
I get compiling error:
Error:(25, 30) Cannot find JsonReader or JsonFormat type class for A
str.parseJson.convertTo[A]
^
How can I fix this error? Can I do this by another way?
Simplifying things, looks like that you've:
The compiler tells you that it cannot find a JsonReader for all possible classes implementing trait Obj
, because you have defined only specific JsonReaders for Error, DataA and DataB.
To solve the problem you can use Either[T,Error]
type for deserialization like:
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
}