Codecs personnalisés
Gérez les structures délicates.
Codecs personnalisés est une leçon Scala for Backend Engineering & Functional Programming gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Scala for Backend Engineering & Functional Programming, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Scala for Backend Engineering & Functional Programming comprend 4 leçons au total.
Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.
When You Need Custom Codecs
Derivation covers the common case, but sometimes JSON does not mirror your case class: legacy field names, encoded enums, or formats like timestamps.
Then you write a Decoder, an Encoder, or both by hand.
A Decoder from a Cursor
The most explicit way to build a decoder is Decoder.instance, receiving an HCursor.
You navigate fields with downField and as, returning an 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)
}forProductN Helpers
For straightforward mappings, Decoder.forProduct2 is more concise: list the JSON keys and pass the constructor.
Helpers exist from forProduct1 up through many arguments.
import io.circe.Decoder
implicit val dec: Decoder[User] =
Decoder.forProduct2("full_name", "years")(User.apply)An Encoder by Hand
Mirror the decoder with Encoder.instance, building a Json object from your fields.
Or use Encoder.forProduct2 to map back to chosen JSON keys with a single call.
import io.circe.Encoder
implicit val enc: Encoder[User] =
Encoder.forProduct2("full_name", "years")(u =>
(u.name, u.age))Transforming Existing Codecs
You rarely start from zero. map adapts a decoder's output and contramap adapts an encoder's input.
emap is like map but can fail, returning Either[String, A] for validation.
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")
}Codecs for Enums
Sealed traits with case objects model enums. Encode each to a tag string and decode by matching that string back.
emap turns an unknown tag into a clean decoding failure.
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")
}Encoding the Enum Back
Pair the enum decoder with a contramap encoder that renders each case to its tag.
Now the sealed trait round-trips as a plain string in JSON.
import io.circe.Encoder
implicit val enc: Encoder[Role] = Encoder[String].contramap {
case Admin => "admin"
case Guest => "guest"
}Custom Codec for Dates
Circe has no built-in java.time codecs in the core module, so dates are a classic custom-codec case.
Decode and encode through the ISO string format.
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)Bundling into a Codec
When you have both directions, combine them into one Codec[A] with Codec.from(decoder, encoder).
This keeps a single implicit in scope instead of two separate ones.
import io.circe.Codec
implicit val roleCodec: Codec[Role] =
Codec.from(dec, enc)Discriminators for ADTs
For sealed hierarchies with data, circe-generic-extras adds a discriminator field instead of a wrapper object.
Configure it once and derive codecs for the whole 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 ShapeImplicit Scope and Priority
A hand-written implicit codec takes precedence over derivation as long as it is in scope. Put it in the companion object so it is always found.
Avoid importing both auto._ and a manual instance for the same type to prevent ambiguity.
Quick Check
Test your understanding of custom codecs.
Recap
Custom codecs handle JSON that does not match your types. Build them with Decoder.instance, forProductN, or transform existing ones via map, contramap, and emap.
Enums and dates are common cases; bundle directions with Codec.from, and use discriminators for ADTs.
Questions Fréquemment Posées
La leçon « Codecs personnalisés » est-elle gratuite ?
Oui — le texte complet de « Codecs personnalisés » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Scala for Backend Engineering & Functional Programming, passe à CoddyKit PRO. Le cours Scala for Backend Engineering & Functional Programming comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Codecs personnalisés » ?
Gérez les structures délicates. Tu pratiques Scala for Backend Engineering & Functional Programming avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Scala for Backend Engineering & Functional Programming ?
Aucune expérience préalable n'est requise. Scala for Backend Engineering & Functional Programming sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Codecs personnalisés » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Scala for Backend Engineering & Functional Programming ?
Oui. Chaque leçon Scala for Backend Engineering & Functional Programming inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Analyser du JSON
- Décoder vers des classes de cas
- Encoder en JSON
- Codecs personnalisés