考慮下面的例子:基於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的更習慣的方法?