Knows Not Much
Knows Not Much

Reputation: 31526

Use Circe to decode Normal Class (not case class)

I have written this code to read and write josn using circe

import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._
case class Foo(i: Int)
val f = Foo(10)
val json = f.asJson.toString
val t1 = decode[Foo](json)

this works very well. But if I create a normal class Bar

class Bar { var i : Int = 0 }
decode[Bar](json)

Now I get error

 could not find implicit value for evidence parameter of type io.circe.Decoder[$sess.cmd25.Bar]

So is it possible to work with normal classes and decode them from json using Circe?

Upvotes: 3

Views: 1490

Answers (2)

Boris Azanov
Boris Azanov

Reputation: 4481

Little addition to LMeyer answer. If your Bar class quite simple, you can write encoder and decoder shortly using some forProduct functions:

import io.circe.{Codec, Decoder, Encoder}
import io.circe.parser._
import io.circe._

class Bar {
  val i: Int = 0
  val j: Option[String] = Some("value")

  override def toString: String =
    s"Bar(i: $i, j: $j)"
}

object Bar {
  implicit val encoder: Encoder[Bar] =
    Encoder.forProduct2[Bar, Int, Option[String]]("i", "j")(
    bar => (bar.i, bar.j)
  )
  implicit val decoder: Decoder[Bar] =
    Decoder.forProduct2[Bar, Int, Option[String]]("i", "j")(
      (iValue, jValue) =>
        new Bar {
          override val i = iValue;
          override val j = jValue
        }
    )
  implicit val codec: Codec[Bar] =
    Codec.forProduct2[Bar, Int, Option[String]]("i", "j")(
      (iValue, jValue) =>
        new Bar {
          override val i = iValue;
          override val j = jValue
        }
    )(bar => (bar.i, bar.j))
}

val json =
  """{"i":42,"j":"Hello"}""".stripMargin

val bar = decode[Bar](json).getOrElse(throw new Exception("Decoding failed"))
// bar: Bar = Bar(i: 42, j: Some(Hello))
println(
  Printer.noSpaces
    .print(Encoder[Bar].apply(bar))
)
// {"i":42,"j":"Hello"}
println(
  Printer.noSpaces
    .print(Encoder[Bar].apply(bar)) == json
)
// true

Upvotes: 0

LMeyer
LMeyer

Reputation: 2631

With io.circe.generic.auto._, you're using Circe's automatic generic derivation, which is backed by Shapeless's LabelledGeneric typeclass. LabelledGeneric only works with product types like tuples and case classes. That's why your seeing this error, because Circe's auto mode could not automatically derive a Decoder instance for your plain class. What you can do is manually implement a decoder for your class (see custom encoders/decoders part).

Upvotes: 6

Related Questions