Codecs personalizados
Gestione estructuras complejas
Codecs personalizados es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
Cuándo necesita códecs personalizados
La derivación cubre los casos habituales, pero a veces el JSON no refleja su case class: puede tener nombres de campos heredados, enumeraciones codificadas o formatos como marcas de tiempo.
En ese caso, escriba manualmente un Decoder, un Encoder o ambos.
Un decodificador a partir de un cursor
La forma más explícita de crear un decodificador es Decoder.instance, que recibe un HCursor.
Navegue por los campos con downField y as, y devuelva 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)
}Ayudantes forProductN
Para asignaciones sencillas, Decoder.forProduct2 es más conciso: indique las claves JSON y pase el constructor.
Hay ayudantes desde forProduct1 hasta funciones con muchos argumentos.
import io.circe.Decoder
implicit val dec: Decoder[User] =
Decoder.forProduct2("full_name", "years")(User.apply)Un codificador manual
Replique el decodificador con Encoder.instance, construyendo un objeto Json a partir de sus campos.
También puede usar Encoder.forProduct2 para asignar los campos a las claves JSON elegidas con una sola llamada.
import io.circe.Encoder
implicit val enc: Encoder[User] =
Encoder.forProduct2("full_name", "years")(u =>
(u.name, u.age))Transformar códecs existentes
Rara vez tendrá que empezar desde cero. map adapta la salida de un decodificador y contramap adapta la entrada de un codificador.
emap funciona como map, pero puede fallar y devolver Either[String, A] para realizar validaciones.
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")
}Códecs para enumeraciones
Las sealed traits con case objects permiten modelar enumeraciones. Codifique cada caso como una cadena identificadora y decodifique comparando de nuevo esa cadena.
emap convierte una etiqueta desconocida en un error de decodificación claro.
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")
}Volver a codificar la enumeración
Combine el decodificador de la enumeración con un codificador contramap que convierta cada caso en su etiqueta.
Así, la sealed trait puede convertirse de ida y vuelta como una cadena simple en JSON.
import io.circe.Encoder
implicit val enc: Encoder[Role] = Encoder[String].contramap {
case Admin => "admin"
case Guest => "guest"
}Códec personalizado para fechas
Circe no incluye códecs integrados para java.time en el módulo principal, por lo que las fechas son un caso clásico para crear un códec personalizado.
Decodifique y codifique usando el formato de cadena 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)Agrupar en un Codec
Cuando tenga ambas direcciones, combínelas en un solo Codec[A] con Codec.from(decoder, encoder).
Así mantiene un único implícito en el ámbito, en lugar de dos separados.
import io.circe.Codec
implicit val roleCodec: Codec[Role] =
Codec.from(dec, enc)Discriminadores para ADT
Para jerarquías selladas con datos, circe-generic-extras añade un campo discriminador en lugar de un objeto envolvente.
Configúrelo una vez y derive los codecs para todo el 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 ShapeÁmbito y prioridad de los implícitos
Un codec implícito escrito a mano tiene prioridad sobre la derivación siempre que esté en el ámbito. Colóquelo en el objeto compañero para que siempre se encuentre.
Evite importar a la vez auto._ y una instancia manual para el mismo tipo, con el fin de prevenir ambigüedades.
Comprobación rápida
Compruebe cuánto ha entendido sobre los codecs personalizados.
Resumen
Los codecs personalizados gestionan JSON que no coincide con sus tipos. Créelos con Decoder.instance, forProductN o transforme los existentes mediante map, contramap y emap.
Los enumerados y las fechas son casos habituales; agrupe ambas direcciones con Codec.from y use discriminadores para los ADT.
Preguntas frecuentes
¿La lección «Codecs personalizados» es gratis?
Sí — el texto completo de «Codecs personalizados» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
¿Qué aprenderé en «Codecs personalizados»?
Gestione estructuras complejas Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?
No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Codecs personalizados»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?
Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Analizar JSON
- Decodificar en case classes
- Codificar en JSON
- Codecs personalizados