running into some Json quirks. I am writing serialize-deserialize logic for an incoming request which contains an object in form of JSON which is IndividualObject. I am using Spray Json for this. Tried using toVector, mapping list of items to resolve the following but not able to resolve the type mismatch.
case class IndividualObject(id: String, path: String)
object IndividualObjectJson extends DefaultJsonProtocol {
implicit val individualObjectFormat = jsonFormat2(IndividualObject.apply)
}
case class IncomingRequest(anotherId: String, indivObjects: Option[List[IndividualObject]])
trait IncomingRequestJson extends SprayJsonSupport with DefaultJsonProtocol {
implici val incomingRequestFormat: RootJsonFormat[IncomingRequest] = new RootJsonFormat[IncomingRequest] {
override def read(json: JsValue): IncomingRequest = {
val fields = json.asJsObject.fields
IncomingRequest(
anotherId = fields("anotherId").convertTo[String]
indivObjects = fields("indivObjects").convertTo[Option[List[IndividualObject]]]
)
override def write(obj: IncomingRequest): JsValue = {
val jsBuilder = Map.newBuilder[String,JsValue]
jsBuilder = "anotherId" -> JsString(obj.anotherId)
jsBuilder = "indivObjects" -> JsArray(obj.indivObjects.get map (IndividualObjectJson.individualObjectFormat))
JsObject(jsBuilder.result())
}
Found the following error in JsArray line: jsBuilder = "indivObjects" -> JsArray(obj.indivObjects.get map (IndividualObjectJson.individualObjectFormat))
Error: type mismatch
found: spray.json.RootJsonFormat[IndividualObject]
required: List[IndividualObject]
Any help is appreciated to understand why its not able to resolve Option[List[....]] for deserialization. Thanks
CodePudding user response:
You can use the jsonFormat2 to create default json readers/writers for case classes with two parameters. The compiler will inject the code via implicit resolution for handling these. But this is not a JsValue(JsString, JsObject, ....). If you create your own Json encoder/encoder you must include JsValue instances manually to create the final JsValue. Something like that:
override def write(obj: IncomingRequest): JsValue = {
val jsBuilder = Map.newBuilder[String, JsValue]
jsBuilder = "anotherId" -> JsString(obj.anotherId)
jsBuilder = "indivObjects" -> JsArray({
obj.indivObjects match {
case Some(list) =>
list
.map(el =>
JsObject(
Map("id" -> JsString(el.id), "path" -> JsString(el.path))
)
)
.toVector
case None => Vector.empty
}
})
JsObject(jsBuilder.result())
}
Something like that should compile.