Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does circe parse a generic type object to Json?

Tags:

scala

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

like image 234
sowen Avatar asked Oct 21 '16 18:10

sowen


People also ask

What is Circe Scala?

Circe is a Scala library that simplifies working with JSON, allowing us to easily decode a JSON string into a Scala object or convert a Scala object to JSON. The library automatically generates the object encoders and decoders, thereby reducing the lines of code we need to work with JSON in Scala.


1 Answers

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.

like image 145
Travis Brown Avatar answered Sep 29 '22 22:09

Travis Brown