在 Circe 中使用没有显式配置依赖的蛇形盒

Using snake case without explicit Configuration dependency in Circe

documentation 中所述,可以将蛇形大小写转换为 Scala 中惯用的驼峰大小写。我试过了,效果很好。在这里:

implicit lazy val configuration: Configuration = Configuration.default.withSnakeCaseMemberNames
@ConfiguredJsonCodec final case class ModelClass(someField1: String, someField2: Int, someField3: String)

我想在不添加对外部框架的依赖的情况下保持我的模型干净,因此它只包含特定于业务的案例 类。

是否可以避免添加注释 @ConfiguredJsonCodec 并将 implicit lazy val configuration: Configuration 纳入范围?也许它可以在 Decoder 级别配置?

完全有可能。这是一个权衡:

  • 如果您的伴生对象中有隐含项,则不必导入它们
  • 如果你不想在你的模型中与库耦合,你必须在 trait/object 中排除所有隐式,然后在每次需要它们时 mixin/import 它们

如果您正在开发具有固定堆栈的应用程序,为每个任务选择库,等等 - 将所有隐式都包含在伴侣中只会更干净,更容易维护。

package com.example

package object domain {

  private[domain] implicit lazy val configuration: Configuration = ...
}
package com.example.domain

import io.circe.generic.extra._

@ConfiguredJsonCodec
final case class ModelClass(...)

许多实用程序都为此进行了优化,例如enumeratum-circe 使用 mixin 将用于枚举的编解码器添加到伴随对象中。

如果你不想让他们在那里,因为例如你有你的模型在一个模块中,它应该是无依赖性的,那么你将不得不把这些暗示放在其他地方。而这需要手动编写代码,无法绕过它:

package com.example.domain

final case class ModelClass(...)
package com.example.domain.circe

import io.circe._
import io.circe.generic.extra.semiauto._

// if I want a mixin:
//   class SomeClass extends Codecs { ... }
trait Codecs {

  protected implicit lazy val configuration: Configuration = ...

  implicit val modelClassDecoder: Decoder[ModelClass] = deriveConfiguredDecoder[ModelClass]
  implicit val modelClassEncoder: Encoder[ModelClass] = deriveConfiguredEncoder[ModelClass]
}

// if I want an import:
//   import com.example.domain.circe.Codecs._
object Circe extends Circe

如果你选择这种方式,你就放弃了,例如enumeraturm-circe 提供编解码器的能力,你将不得不手动编写它们。

您必须根据您的用例选择其中之一,但您不能同时获得两者的好处:要么放弃样板文件减少,要么放弃依赖性减少。