I'm trying to switch my JsonUtils class from Json4s to circe
and i find it hard to solve the generic implementation for the decoder.
my Json4s func look like this:
implicit val formats = DefaultFormats
def extractValueFromJson[T](json: String, key: String)(implicit m: Manifest[T]): T = {
val parsed = parse(json).asInstanceOf[JObject]
val value =(parsed \ key).extract[T]
value
}
example of usage:
extractValueFromJson[String](jsonStr, keyInJson)
and it is working perfectly
now i have tried the same func with circe:
implicit def decodeGeneric[A: Decoder](json: Json): Either[Error, A] = Decoder[A].decodeJson(json)
def extractValueFromJson[A: ClassTag, T](jsonStr: String, key: String)(implicit m: Manifest[T]): T = {
val json: String = jsonStr.asJson.noSpaces
decode[A](json) match {
case Left(error: Error) => throw error
case Right(value) => {
value.getClass.getDeclaredField(key).get(value).asInstanceOf[T]
}
}
}
and i get the following error while compiling:
could not find implicit value for evidence parameter of type io.circe.Decoder[A]
[error] decode[A](json) match {
[error] ^
This is the desired output for a given input
input:
case class Bar(str: String)
val bar = Bar("just a string")
usage:
val test = extractValueFromJson[Bar,String](bar.asJson.noSpaces,"str")
output:
just a string
What am i doing wrong here? Is there a way to define a generic decoder? i have read some similar questions here but haven't found a solution that fit my needs
You can do this:
def extractValueFromJson[A](jsonStr: String, key: String)(implicit decoder: Decoder[A]): A =
io.circe.parser.decode(jsonStr)(decoder.at(field = key)) match {
case Right(result) => result
case Left(error) => throw error
}
Which you can use like this:
extractValueFromJson[String](jsonStr = bar.asJson.noSpaces, key = "str")
// res: String = "just a string"