Migrating for Json4S to Circe

1.9k views Asked by At

I have the following code written in json4s which compiles and works fine

import org.json4s._
def jsonRead[T <: AnyRef](input: String)(implicit m: Manifest[T]): T = {
    Try(read[T](input)).get
}

def jsonWrite[T <: AnyRef](input: T)(implicit m: Manifest[T]): String = {
    write[T](input).toString
}

I have written the following Circe code

import io.circe._
import io.circe.syntax._
import io.circe.generic.auto._
import io.circe.parser.decode
def unmarshall[T <: AnyRef](input: String)(implicit m: Manifest[T]) : T ={
    decode[T](input).right.get
}
def marshall[T <: AnyRef](input: T)(implicit m: Manifest[T]) : String = {
    input.asJson.toString
}

But I get the error

Error:(27, 16) could not find implicit value for parameter decoder: io.circe.Decoder[T] decode[T](json).right.get
Error:(27, 16) not enough arguments for method decode: (implicit decoder: io.circe.Decoder[T])Either[io.circe.Error,T]. Unspecified value parameter decoder. decode[T](json).right.get
Error:(30, 11) could not find implicit value for parameter encoder: io.circe.Encoder[T] obj.asJson.toString
Error:(30, 11) not enough arguments for method asJson: (implicit encoder: io.circe.Encoder[T])io.circe.Json. Unspecified value parameter encoder.    obj.asJson.toString
1

There are 1 answers

0
mariop On BEST ANSWER

json4s and circe are different libraries that work in different ways and that's why you can't use the same technique. While json4s read needs a Manifest to extract a value from Json, circe requires an instance of the typeclass Decoder. If you want to use circe in your example you should write something like

def unmarshall[T <: AnyRef](input: String)(implicit d: Decoder[T]) : T = {
    decode[T](input).right.get
}
def marshall[T <: AnyRef](input: T)(implicit e: Encoder[T]) : String = {
    input.asJson.toString
}

To understand the differences I suggest to read both implementation, they are very useful to understand how the two libraries do what they do. You can see the differences already in the signatures of json4s native read and circe decode. I will copy here the important bits of the signatures to explain the fundamental difference between the two libraries. The signature of json4s native read is

def read[A](input: String)(implicit mf: Manifest[A]): A

which can be interpreted as "I can convert a String into any type A if you provide a Scala Manifest for it". Because Manifest is a Scala trait used for reflection, you can deduce that read will use reflection.

The signature of circe decode is different:

def decode[A](input: String)(implicit d: Decoder[A]): Either[Error, A]

which can be read as "I can try to convert a String into a type A if you provide a circe Decode instance for it". The Decoder typeclass just tells the system how to decode a value of type A from json.