Reputation: 61
The application I am developing has to decode json from a data source which for a given field may return either a List[String] or a List[Double]. I want to decode this json into a case class so i can process the data.
[{
"id": 123,
"latlng": ["-12.777", "18.776"]
}, {
"id": 123,
"latlng": [-12.777, 18.776]
}]
Im using circe 0.11.1
currently my case class looks like
case class Report(id:Int, latlng:Either[List[String],List[Double]])
and my decoding code
decode[List[Report]](testData)
i receive the error
DecodingFailure at [0].latlng: [A, B]Either[A, B]
Upvotes: 1
Views: 241
Reputation: 1163
It sounds like you already have a solution that works for you. I found a solution to your original problem though. It is not very elegant, but it works. There might be a more elegant solution that involves the Validated monad in Cats library, but I am not familiar enough with the Cats library to write it in that way.
import io.circe._
import io.circe.parser._
object Main {
def main(args: Array[String]) = {
val testData =
"""
|[{
| "id": 123,
| "latling": ["-12.777", "18.776"]
|}, {
| "id": 123,
| "latling": [-12.777, 18.776]
|}]
""".stripMargin
println(decode[List[Report]](testData))
}
case class Report(id: Int, latling: Either[List[String],List[Double]])
object Report {
implicit val reportDecoder: Decoder[Report] = new Decoder[Report] {
override def apply(c: HCursor): Decoder.Result[Report] = {
val stringAttempt = for {
id <- c.downField("id").as[Int]
latlingString <- c.downField("latling").as[List[String]]
} yield Report(id, Left(latlingString))
val doubleAttempt = for {
id <- c.downField("id").as[Int]
latlingDouble <- c.downField("latling").as[List[Double]]
} yield Report(id, Right(latlingDouble))
stringAttempt match {
case Right(stringValue) => Right(stringValue)
case Left(stringFailure) => doubleAttempt
}
}
}
}
}
You can run by starting up sbt with
sbt
and running
runMain Main
Here is my build.sbt file:
name := "stackoverflow20190821"
version := "0.1"
scalaVersion := "2.12.0"
val circeVersion = "0.11.1"
libraryDependencies ++= Seq(
"io.circe" %% "circe-core",
"io.circe" %% "circe-generic",
"io.circe" %% "circe-parser"
).map(_ % circeVersion)
Upvotes: 1