有多种方法可以实现这一点。我假设你不会从头开始构建编解码器并使用已经存在于circe中的内容。
默认参数 + generic-extras
有一个叫做 `circe-generic-extras` 的软件包,它允许对自动派生的编解码器进行一些定制。特别是,它允许您使用默认参数作为回退值。
缺点是它在编译时速度较慢,并且需要在范围内拥有一个隐式的 `io.circe.generic.extras.Configuration`。
所以,首先你需要那个隐式配置:
object Configs {
implicit val useDefaultValues = Configuration.default.withDefaults
}
通常将此内容放入项目中的某个通用工具包中,以便您可以轻松地重用这些配置。
然后,在您的类上使用@ConfiguredJsonCodec
宏注释,或在其伴生对象中使用extras.semiauto.deriveConfiguredCodec
:
import Configs.useDefaultValues
@ConfiguredJsonCodec
case class Foo(
id: String,
name: String,
field1: Boolean,
field2: Boolean,
field3: Boolean = false,
field4: Boolean = false
)
不要忘记导入配置,也不要同时导入多个配置文件。否则,您将收到一个无用的错误提示信息,例如:
could not find Lazy implicit value of type io.circe.generic.extras.codec.ConfiguredAsObjectCodec[Foo]
这就足以解码
Foo
,即使默认值字段缺失:
println {
io.circe.parser.decode[Foo]("""
{
"id": "someid",
"name": "Gordon Freeman",
"field1": false,
"field2": true
}
""")
}
自包含的 scastie 点击此处。
回退解码器
思路如下:使用单独的 case class 描述旧数据格式,并构建一个解码器来尝试将数据解析为新旧格式。Circe 解码器具有 or
组合器,可用于尝试此类解析。
在这里,首先描述了“旧”数据格式及其升级到新格式的方法:
@JsonCodec(decodeOnly = true)
case class LegacyFoo(
id: String,
name: String,
field1: Boolean,
field2: Boolean,
) {
def upgrade: Foo =
Foo(id, name, field1, field2, false, false)
}
有了新的格式,您必须手动加入编解码器,因此您不能使用宏注释。不过,您可以使用generic.semiauto.deriveXXX
方法,这样就不必自己列出所有字段:
case class Foo(
id: String,
name: String,
field1: Boolean,
field2: Boolean,
field3: Boolean,
field4: Boolean
)
object Foo {
implicit val encoder: Encoder[Foo] = semiauto.deriveEncoder[Foo]
implicit val decoder: Decoder[Foo] =
semiauto.deriveDecoder[Foo] or Decoder[LegacyFoo].map(_.upgrade)
}
同样的有效负载,这也会“正常工作”:
println {
io.circe.parser.decode[Foo]("""
{
"id": "someid",
"name": "Gordon Freeman",
"field1": false,
"field2": true
}
""")
}
点击此处访问Scastie。
第一种方法需要额外的库,但少了很多样板代码。它还允许调用者提供 field4
但不提供 field3
- 在第二种方法中,如果出现这种情况,field4
的值将被完全忽略。
第二种方法可以处理比“加入默认值的字段”更复杂的变化,例如从几个其他值计算值或更改集合内部结构,并且在以后需要时也可以有多个版本。
哦,你还可以将 LegacyFoo
放入 object Foo
中,并使其私有化,如果你不想公开额外的数据类型。
Foo
case类。即使我们将默认值设置为field3
,如果在响应中缺少它,Circe也会失败并显示错误Attemp to decode value on failed cursor
。 - wtian