Reputation: 1088
Here is what I am trying to do
case class MessageModel (time: Long, content: String) {}
val message = MessageModel(123, "Hello World")
def jsonParser[A] (obj: A) : String = obj.asJson.noSpaces
println jsonParser[MessageModel](message)
this doesn't work, because it will complain Error:(13, 8) could not find implicit value for parameter encoder: io.circe.Encoder[A] obj.asJson.noSpaces ^
I kind of understand why it is happening, but is there a way to work around it?
Thanks
Upvotes: 6
Views: 3598
Reputation: 139058
Encoding and decoding in circe are provided by type classes, which means that you have to be able to prove at compile time that you have a type class instance for A
if you want to encode (or decode) a value of type A
.
This means that when you write something like this:
import io.circe.syntax._
def jsonPrinter[A](obj: A): String = obj.asJson.noSpaces
You're not providing enough information about A
for circe to be able to print values of that type. You can fix this with a context bound:
import io.circe.Encoder
import io.circe.syntax._
def jsonPrinter[A: Encoder](obj: A): String = obj.asJson.noSpaces
Which is Scala's syntactic sugar for something like this:
def jsonPrinter[A](obj: A)(implicit encoder: Encoder[A]): String =
obj.asJson.noSpaces
Both of these will compile, and you can pass them a value of any type that has an implicit Encoder
instance. For your MessageModel
specifically, you could use circe's generic derivation, since it's a case class:
scala> import io.circe.generic.auto._
import io.circe.generic.auto._
scala> case class MessageModel(time: Long, content: String)
defined class MessageModel
scala> val message = MessageModel(123, "Hello World")
message: MessageModel = MessageModel(123,Hello World)
scala> jsonPrinter(message)
res0: String = {"time":123,"content":"Hello World"}
Note that this wouldn't work without the auto
import, which is providing Encoder
instances for any case class (or sealed trait hierarchy) whose members are all also encodeable.
Upvotes: 8