I receive JSON response from an upstream server that I do not have a control on, for modification.
The JSON could have the following format
{"data":[["Some_text","boolean",["key_string1","key_string2"]]]}
Or it could also show up as
{"data":[["Some_text","boolean","key_string2"]]}
Or it could show up as a combination of the two.
{"data":[["Some_text","boolean",["key_string1","key_string2"]],["Some_text","boolean","key_string2"]]}
Individually I can define the READS for each format if they don't mix. However, given that the data may be of mixed format, I am unable to wrap my head around how the Reads should be written so as to check if the underlying type is a string or array before transforming it?
Is it possible to say something like
(
(JsPath)(0).read[String] and
(JsPath)(1).read[Boolean] and
(JsPath)(2).read( **if type is simple, String OR if type is array, then seq** )
)(SomeGloriousCaseClass)
How can I approach this problem of deserializing?
For fun I implemented a solution. You might need to tweak it a bit :
private def toSeq(jsValue: JsValue): JsResult[Seq[String]] = {
jsValue match {
case JsArray(es:Seq[JsValue]) ⇒ sequence(es.map(e ⇒ toSeq(jsValue))).map(_.flatten)
case JsString(s) ⇒ JsSuccess(s :: Nil)
case _ ⇒ JsError("INVALID")
}
}
private def sequence[A](seq:Seq[JsResult[A]]):JsResult[Seq[A]] = {
seq.foldLeft(JsResult.applicativeJsResult.pure(Seq[A]()))((acc, next) ⇒ for(acc2 ← acc; next2 ← next) yield acc2 :+ next2)
}
Hope it helps and would be glad to provide further explanations if needed.