考虑下面的例子:基于JSON结构解码Argonaut中的密封特质?
sealed trait Id
case class NewId(prefix: String, id: String) extends Id
case class RevisedId(prefix: String, id: String, rev: String) extends Id
case class User(key: Id, name: String)
val json = """
{
"key": {
"prefix": "user",
"id": "Rt01",
"rev": "0-1"
},
"name": "Bob Boberson"
}
"""
implicit val CodecUser: CodecJson[User] = casecodec2(User.apply, User.unapply)("key", "name")
implicit val CodecId: CodecJson[Id] = ???
json.decodeOption[User]
我需要编写Id
当它具有适当的结构,将解码对象的CodecJson
。
添加某种歧视字段是一个常见的建议,但我不想更改我已经生产/使用的和json4s
的JSON。
在那些库中,您的编码器/解码器基本上只是PartialFunction[JValue, A]
和PartialFunction[A, JValue]
。如果您的值未在域中定义,那就是失败。这是一个非常简单,优雅的解决方案,我认为。除此之外,您还有JSON类型的提取器,因此可以很容易地在字段/结构上匹配对象。
被提进了一步,让字段顺序不重要,忽略不匹配字段的存在,所以你可能只是这样做:
case json"""{ "prefix": $prefix, "id": $id, "rev": $rev }""" =>
RevisedId(prefix, id, rev)
这是很简单/强大。
我无法弄清楚如何做与argonaut
类似的工作。这是我迄今为止最好的:
val CodecNewId = casecodec2(NewId.apply, NewId.unapply)("prefix", "id")
val CodecRevisedId = casecodec3(RevisedId.apply, RevisedId.unapply)("prefix", "id", "rev")
implicit val CodecId: CodecJson[Id] =
CodecJson.derived[Id](
EncodeJson {
case id: NewId => CodecNewId(id)
case id: IdWithRev => RevisedId(id)
},
DecodeJson[Id](c => {
val q = RevisedId(c).map(a => a: Id)
q.result.fold(_ => CodecNewId(c).map(a => a: Id), _ => q)
})
)
所以有一些问题。我必须定义我不打算使用的额外编解码器。我没有在EncodeJson
中为CodecJson[Id]
使用案例级提取器,而是委托给我定义的其他编码器。对于只有2或3个字段的课程,只是感觉不太直接或不干净。
DecodeJson
部分的代码也很杂乱。除了fold
的ifEmpty
一侧的其他类型外,它与DecodeJson.|||
中的代码相同。
没有人有写的总和,类型有一个基本的编解码器中淘金是不需要鉴别而是可以匹配在结构的JSON的更习惯的方法?