Problem Description
I have a case class Student that includes instances of the Animal trait, along with two case classes Cat and Dog that extend the trait. I'm having trouble figuring out how to properly encode and decode instances of the Student class.
Goals Understand how to correctly encode a Student instance to JSON. Learn the appropriate decoding process for a JSON representation back to a Student instance.
import io.circe._
import io.circe.generic.semiauto._
trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
case class Student(id: Int, name: String, animal: Animal)
object Student {
implicit val catEncoder: Encoder[Cat] = deriveEncoder
implicit val catDecoder: Decoder[Cat] = deriveDecoder
implicit val dogEncoder: Encoder[Dog] = deriveEncoder
implicit val dogDecoder: Decoder[Dog] = deriveDecoder
implicit val animalEncoder: Encoder[Animal] = deriveEncoder
implicit val animalDecoder: Decoder[Animal] = deriveDecoder
implicit val studentEncoder: Encoder[Student] = deriveEncoder
implicit val studentDecoder: Decoder[Student] = deriveDecoder
}
object Test extends App {
import io.circe.syntax._
val student = Student(1, "abc", Cat("cat"))
val jsonString = student.asJson.noSpaces
println("JSON representation: " + jsonString)
val decoded: Either[io.circe.Error, Student] = io.circe.parser.decode[Student](jsonString)
println("Decoded Student: " + decoded)
}
If you'd like to derive a type class (codec) for a parent trait of hierarchy then the trait must be sealed
https://scastie.scala-lang.org/DmytroMitin/td1vmuCESZePhxno7VYwUw/4
Also on contrary to
Student
, forCat
,Dog
,Animal
the instances of type classesEncoder
/Decoder
are placed now out of implicit scope.Where does Scala look for implicits?
Implicits of types
SomeTypeclass[SomeDatatype]
should be placed to companion objects ofSomeTypeclass
orSomeDatatype
. Then the implicits will be available without import. You can check that althoughimplicitly[Decoder[Student]]
compiles but for exampleimplicitly[Decoder[Cat]]
doesn't. So you should better writehttps://scastie.scala-lang.org/DmytroMitin/td1vmuCESZePhxno7VYwUw/2
Also
Encoder
+Decoder
is justCodec
https://scastie.scala-lang.org/DmytroMitin/td1vmuCESZePhxno7VYwUw/5