3 votes

Scala/Play : modifier le comportement de la macro Json.format pour un seul champ

J'ai une grande classe de cas avec plus de 10 champs, qui représente un payload JSON, qui vient de l'utilisateur. La plupart des champs sont optionnels, donc j'utilise Option dans ce cas ( Option[String] pour les champs de type chaîne de caractères. C'est une bonne approche, jusqu'à ce que j'aie besoin d'une séquence optionnelle. Je pense qu'écrire Option[Seq[String]] est bizarre, car une séquence vide suffit à montrer qu'il n'y a pas de données (pour quelque raison que ce soit). Je pourrais cependant gérer cela de manière manuelle :

implicit val reads = new Reads[MyCaseClass] {
  def reads(js: JsValue): JsResult[MyCaseClass] = {
    JsSuccess(MyCaseClass(
      (js \ "unit_code").as[String],
      // other fields omited
      (js \ "positions").asOpt[Seq[String]] match {
        case Some(seq: Seq[String]) => seq
        case None => Seq.empty[String]
      }
    ))
  }
}

Mais je ne veux pas écrire toutes ces choses manuellement. Il pourrait y avoir des erreurs, je dois les tester séparément, et, à coup sûr, cela prend beaucoup plus de temps que d'écrire implicit val f = Json.format[MyCaseClass] .

Existe-t-il une option permettant de traiter séparément un seul champ et de laisser les autres champs traités dans la macro par défaut ?

1voto

AlexB Points 30

Merci à l'utilisateur 'cchantep' de pointer vers Json transformateurs . C'est ainsi que j'ai résolu le problème :

Classe de cas :

case class MyCaseClass(unit_code: String, positions: Seq[String] = Seq.empty)

Objet d'accompagnement

object MyCaseClass {
  private val readsTransformer: Reads[JsObject] =  __.json.update(
    __.read[JsObject]
      .map{ o =>
        if (o.keys.exists(p => p.equals("positions"))) {
          o
        } else {
          o ++ Json.obj("positions" -> JsArray())
        }
      }
  )
  implicit val readsImplicit: Reads[MyCaseClass] = readsTransformer.andThen(Json.reads[MyCaseClass])
  implicit val writesImplicit: OWrites[MyCaseClass] = Json.writes[MyCaseClass]
}

Cela semble un peu lourd, mais il est possible d'écrire une fonction commune qui crée un transformateur pour le champ exact, de sorte que dans chaque objet compagnon, ce ne serait pas si verbeux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X