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



如文档中指定的那样,可以将蛇案转换为骆驼壳,这在 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中的所有隐式,然后在每次需要它们时混合/导入它们

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

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 使用混合蛋白将用于枚举的添加编解码器添加到伴随对象中。

如果你不想把它们放在那里,因为例如,你的模型在一个模块中,它应该是无依赖的,那么你就必须把这些隐式的东西放在其他地方。这需要手动编写代码,没有办法解决它:

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提供编解码器的能力,你将不得不手动编写它们。

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