Skip to content

Instantly share code, notes, and snippets.

@TonioGela
Created December 21, 2022 09:31
Show Gist options
  • Select an option

  • Save TonioGela/4c8d7dfe001668bc9908336a1daa6f94 to your computer and use it in GitHub Desktop.

Select an option

Save TonioGela/4c8d7dfe001668bc9908336a1daa6f94 to your computer and use it in GitHub Desktop.
//> using scala "2.13.10"
//> using lib "io.spray::spray-json::1.3.6"
import spray.json._
// il tuo wrapper di cose nullabili
sealed trait PatchValue[+T]
object PatchValue {
object ToDelete extends PatchValue[Nothing]
case class Value[T](t: T) extends PatchValue[T]
}
// il tuo modello di dominio, il body della tua patch
// l'idea e' che tu abbia anche un modello "User(name:String, surname:String)" nella tua codebase
case class UserDelta(
name: Option[PatchValue[String]],
surname: Option[PatchValue[String]]
)
object Main extends App {
// un deser scritto a mano, non ha molto senso che sia un RootJsonFormat perche'
// non creerai mai un json a partire da UserDelta ma solo uno UserDelta da un json
// (RootJsonFormat == RootJsonReader + RootJsonWriter)
implicit val userDeltaFormat = new RootJsonReader[UserDelta]
with DefaultJsonProtocol {
override def read(json: JsValue): UserDelta = json match {
case JsObject(fields) => {
val name: Option[PatchValue[String]] = fields.get("name") match {
case None => None
case Some(JsNull) => Some(PatchValue.ToDelete)
case Some(JsString(s)) => Some(PatchValue.Value(s))
case Some(_) => deserializationError("name should be a string!")
}
// i due approcci sono equivalenti, se me lo chiedi, preferisco il map
val surname: Option[PatchValue[String]] = fields.get("surname").map {
case JsNull => PatchValue.ToDelete
case JsString(s) => PatchValue.Value(s)
case _ => deserializationError("surname should be a string!")
}
UserDelta(name, surname)
}
case _ => deserializationError("User delta expected")
}
}
val json1:String = """{ "name":null, "surname":"foo" }"""
val json2:String = """{ "name":"pippo"}"""
val json3:String = """{ "surname":"paperino"}"""
println(s"${json1} ==> ${json1.parseJson.convertTo[UserDelta]}\n")
println(s"${json2} ==> ${json2.parseJson.convertTo[UserDelta]}\n")
println(s"${json3} ==> ${json3.parseJson.convertTo[UserDelta]}\n")
}
@TonioGela

Copy link
Copy Markdown
Author

Runnare con scala-cli run nullableJsonField.scala

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment