Custom Jackson JSON serializer/deserializer from Circe
Snippet for when you’re using Circe and want to define custom Jackson serializers/deserializers from Circe’s codec definitions.
It’s not very efficient, as deserialization seems to parse the JSON in both Jackson and Circe, but I don’t have better ideas.
import com.fasterxml.jackson.core.{ JsonGenerator, JsonParser, TreeNode }
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import com.fasterxml.jackson.databind.{ DeserializationContext, SerializerProvider }
import io.circe.parser.decode
import io.circe.syntax._
import io.circe.{ Decoder, Encoder }
import scala.reflect.ClassTag
class JacksonSerializerFromCirce[A: ClassTag: Encoder]
extends StdSerializer[A](
    implicitly[ClassTag[A]].runtimeClass.asInstanceOf[Class[A]]
  ) {
  override def serialize(
    value: A,
    gen: JsonGenerator,
    provider: SerializerProvider
  ): Unit = {
    val json = value.asJson.noSpaces
    gen.writeRawValue(json)
  }
}
class JacksonDeserializerFromCirce[A: ClassTag: Decoder]
  extends StdDeserializer[A](
    implicitly[ClassTag[A]].runtimeClass.asInstanceOf[Class[A]]
  ) {
  override def deserialize(
    p: JsonParser,
    ctxt: DeserializationContext
  ): A = {
    decode[A](p.readValueAsTree[TreeNode]().toString) match {
      case Right(a) => a
      case Left(e) => throw e
    }
  }
}
Usage:
import io.circe.Codec
import io.circe.generic.semiauto.deriveCodec
@JsonSerialize(using = classOf[Sample.Serializer])
@JsonDeserialize(using = classOf[Sample.Deserializer])
final case class Sample(
  name: String,
  isActive: Boolean
)
object Sample {
  implicit val codec: Codec[Sample] =
    deriveCodec
  class Serializer
    extends JacksonSerializerFromCirce[Sample]
  class Deserializer
    extends JacksonDeserializerFromCirce[Sample]
}
  
    
    
    | Written by Alexandru Nedelcu