Codec personalizzati
Gestisca strutture complesse.
Codec personalizzati è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Quando servono codec personalizzati
La derivazione copre i casi più comuni, ma talvolta il JSON non rispecchia la case class: può avere nomi di campo legacy, enum codificati o formati come i timestamp.
In questi casi scrive manualmente un Decoder, un Encoder o entrambi.
Un decoder a partire da un cursore
Il modo più esplicito per costruire un decoder è Decoder.instance, che riceve un HCursor.
Esplori i campi con downField e as, restituendo un Either.
import io.circe.Decoder
case class User(name: String, age: Int)
implicit val dec: Decoder[User] = Decoder.instance { c =>
for {
n <- c.downField("full_name").as[String]
a <- c.downField("years").as[Int]
} yield User(n, a)
}Helper forProductN
Per le corrispondenze più semplici, Decoder.forProduct2 è più conciso: elenchi le chiavi JSON e passi il costruttore.
Sono disponibili helper da forProduct1 fino a un numero elevato di argomenti.
import io.circe.Decoder
implicit val dec: Decoder[User] =
Decoder.forProduct2("full_name", "years")(User.apply)Un encoder scritto manualmente
Riproduca la logica del decoder con Encoder.instance, costruendo un oggetto Json a partire dai campi.
In alternativa, usi Encoder.forProduct2 per associare i campi alle chiavi JSON scelte con una sola chiamata.
import io.circe.Encoder
implicit val enc: Encoder[User] =
Encoder.forProduct2("full_name", "years")(u =>
(u.name, u.age))Trasformazione di codec esistenti
Raramente si parte da zero. map adatta l'output di un decoder, mentre contramap adatta l'input di un encoder.
emap è simile a map, ma può fallire e restituire Either[String, A] per eseguire la validazione.
import io.circe.Decoder
case class Age(value: Int)
implicit val dec: Decoder[Age] =
Decoder[Int].emap { i =>
if (i >= 0) Right(Age(i)) else Left("negative age")
}Codec per gli enum
Le sealed trait con case object rappresentano gli enum. Codifichi ciascun caso in una stringa tag e lo decodifichi confrontando nuovamente quella stringa.
emap trasforma un tag sconosciuto in un errore di decodifica chiaro.
sealed trait Role
case object Admin extends Role
case object Guest extends Role
implicit val dec: Decoder[Role] = Decoder[String].emap {
case "admin" => Right(Admin)
case "guest" => Right(Guest)
case other => Left(s"unknown role: $other")
}Ricodifica dell'enum
Abbini al decoder dell'enum un encoder con contramap che rappresenti ogni caso con il relativo tag.
La sealed trait può così essere convertita avanti e indietro come una semplice stringa JSON.
import io.circe.Encoder
implicit val enc: Encoder[Role] = Encoder[String].contramap {
case Admin => "admin"
case Guest => "guest"
}Codec personalizzato per le date
Circe non include codec integrati per java.time nel modulo core, quindi le date sono un tipico caso d'uso per un codec personalizzato.
Decodifichi e codifichi utilizzando il formato stringa ISO.
import java.time.LocalDate
import io.circe.{Decoder, Encoder}
implicit val dec: Decoder[LocalDate] =
Decoder[String].map(LocalDate.parse)
implicit val enc: Encoder[LocalDate] =
Encoder[String].contramap(_.toString)Raggruppamento in un Codec
Quando dispone di entrambe le direzioni, le combini in un unico Codec[A] con Codec.from(decoder, encoder).
In questo modo mantiene nell'ambito un solo implicito invece di due distinti.
import io.circe.Codec
implicit val roleCodec: Codec[Role] =
Codec.from(dec, enc)Discriminatori per gli ADT
Per le gerarchie sealed con dati, circe-generic-extras aggiunge un campo discriminatore invece di un oggetto wrapper.
Lo configuri una volta e derivi i codec per l'intero ADT.
import io.circe.generic.extras._
implicit val cfg: Configuration =
Configuration.default.withDiscriminator("type")
@ConfiguredJsonCodec sealed trait Shape
@ConfiguredJsonCodec case class Circle(r: Double) extends ShapeAmbito e priorità degli impliciti
Un codec implicito scritto manualmente ha la precedenza sulla derivazione, purché si trovi nell'ambito. Lo inserisca nell'oggetto companion, così verrà sempre trovato.
Eviti di importare sia auto._ sia un'istanza manuale per lo stesso tipo, per prevenire ambiguità.
Verifica rapida
Verifichi la propria comprensione dei codec personalizzati.
Riepilogo
I codec personalizzati gestiscono JSON che non corrisponde ai propri tipi. Li costruisca con Decoder.instance, forProductN oppure trasformi quelli esistenti tramite map, contramap ed emap.
Gli enum e le date sono casi comuni; raggruppi le due direzioni con Codec.from e usi i discriminatori per gli ADT.
Domande Frequenti
La lezione «Codec personalizzati» è gratuita?
Sì — il testo completo di «Codec personalizzati» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Cosa imparerò in «Codec personalizzati»?
Gestisca strutture complesse. Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?
Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Codec personalizzati»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?
Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Analizzare JSON
- Decodificare in case class
- Codificare in JSON
- Codec personalizzati