【发布时间】:2017-01-11 12:57:06
【问题描述】:
如果 json 不完整(缺少某些字段),我需要从案例类实例创建一个更新的实例(任何需要的 DecodeJsons 隐式派生)。如何使用 Argonaut(最好)或 Circe(如果必须的话)来实现这一点?
例子:
case class Person(name:String, age:Int)
val person = Person("mr complete", 42)
val incompletePersonJson = """{"name":"mr updated"}"""
val updatedPerson = updateCaseClassFromIncompleteJson(person, incompletePersonJson)
println(updatedPerson)
//yields Person(mr updated, 42)
我很确定我必须将 json 解析为 json AST,然后将其转换为 Shapeless LabelledGeneric,然后以某种方式使用 Shapeless 更新来更新案例类实例。
编辑 2
在阅读了 Shapeless 源代码后,我发现我可以生成自己的“默认”对象。我设法创建了一个解决方案,该解决方案需要在解析 json 时存在案例类的实例。我希望避免这种情况,而是稍后提供实例。无论如何,它是:
import shapeless._
import argonaut._
import ArgonautShapeless._
import shapeless.ops.hlist.Mapper
case class Person(name: String, age: Int)
object MkDefault {
object toSome extends Poly1 {
implicit def default[P] = at[P](Some(_))
}
def apply[P, L <: HList, D <: HList]
(p: P)
(implicit
g: Generic.Aux[P, L],
mpr: Mapper.Aux[toSome.type, L, D]
): Default.Aux[P, mpr.Out] =
Default.mkDefault[P, D](mpr(g.to(p)))
}
object Testy extends App {
implicit val defs0 = MkDefault(Person("new name? NO", 42))
implicit def pd = DecodeJson.of[Person]
val i = """{"name":"Old Name Kept"}"""
val pp = Parse.decodeOption[Person](i).get
println(pp)
}
这会产生Person(Old Name Kept,42)。
【问题讨论】:
-
调试 ArgonautShapeless' DecodeJson 推断 (ArgonautShapeless.derivedDecodeJson),我看到一个对象 defaults=Defaults$AsOptions$$anon$9 用值 None :: None :: HNil 实例化。对我来说,如果我能以某种方式用我自己提供的隐式实例替换它,我可以默认以某种方式填充缺失的 json。
-
我能想到的唯一能以类型安全的方式实现的是将现有案例类重新序列化为 json,将两者都转换为 Map[String, Any],然后合并映射,转换回 json,然后重新解析
-
@Falmarri 这实际上并不是一个坏主意,我会记住它作为备份解决方案,因为它显然需要更多的时间和计算机资源。
标签: json scala shapeless argonaut circe