Home > Enterprise >  Circe alternative for Jackson PropertyNamingStrategy
Circe alternative for Jackson PropertyNamingStrategy

Time:11-23

We are moving from using Jackson to Circe.

To shorten the discussion I have for example the following case class:

import com.fasterxml.jackson.databind.PropertyNamingStrategies

@JsonNaming(classOf[PropertyNamingStrategies.SnakeCaseStrategy])
final case class User(
    firstName: Option[Boolean] = None,
    lastName: Option[String] = None,
)

This makes sure that the external service responding with

{
  "first_name": "John", 
  "last_name": "Doe"
}

Gets mapped properly. But I am struggling to find Circe alternative for this. I am positive there must be a built in config somewhere, I am just not reading the docs correctly

CodePudding user response:

You can use Circe Generic Extras:

final case class User(
    firstName: Option[Boolean] = None,
    lastName: Option[String] = None,
)
object User {  
  import io.circe.generic.extras.Configuration
  implicit val customConfig: Configuration =
    Configuration.default.withSnakeCaseMemberNames

  import io.circe.generic.extras.semiauto._
  implicit val encoder: Encoder[User] = deriveConfiguredEncoder
  implicit val decoder: Decoder[User] = deriveConfiguredDecoder
}

In Scala 2 you could reduce some bolierplate with:

import io.circe.generic.extras.semiauto.ConfiguredJsonCodec

@ConfiguredJsonCodec
final case class User(
    firstName: Option[Boolean] = None,
    lastName: Option[String] = None,
)
object User {
  import io.circe.generic.extras.Configuration
  // this config can be put somewhere else if you want to share it
  // e.g. in package object of the package - but I'd add private[packagename]
  // to limit its scope to just this package
  implicit val customConfig: Configuration =
    Configuration.default.withSnakeCaseMemberNames
}

Unfortunately, as I am writing this, it hasn't been adjusted for Scala 3, I see no build-in derived method in these classes, so you cannot do just

final case class User(
    firstName: Option[Boolean] = None,
    lastName: Option[String] = None,
) derives ConfiguredEncoder, ConfiguredDecoder
object User {
  import io.circe.generic.extras.Configuration
  implicit val customConfig: Configuration =
    Configuration.default.withSnakeCaseMemberNames
}

But maybe it will be added in future so Scala 3 version could have as little boilerplate as Scala 2.

  • Related