使用 Argonaut 或 Circe 从不完整 JSON 更新案例 class
Update case class from incomplete JSON with Argonaut or Circe
我需要从案例 class 实例(任何需要的 DecodeJson
隐式派生)创建一个更新的实例,给定一个不完整的 json(某些字段缺失)。如何使用 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,然后将其转换为无形 LabelledGeneric
,然后以某种方式使用无形更新来更新大小写 class实例。
编辑 2
阅读 Shapeless 源代码后,我发现我可以生成自己的 "Default"-object。我设法创建了一个解决方案,该解决方案要求在解析 json 时存在案例 class 的实例。我希望避免这种情况,而是稍后提供实例。不管怎样,它是:
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)
。
您可以在 Person
上生成带有宏注释的那些 implicit val defs / pd
(例如,在 object Person
中,并执行 import Person._
以召唤隐式)。有关使用示例,请参阅 this scalameta 中未完成的 Simulacrum(scala-reflect 也很好,但似乎 scalameta 就足够了)。此外,您还必须在某处指定缺少的默认值(42
),例如,如果 class 构造函数(age: Int = 42
,识别也可以在宏中完成)。
为了完整起见:自 0.2 版本以来,已在 circe 中提供了对 "patching" 实例的支持:
import io.circe.jawn.decode, io.circe.generic.auto._
case class Person(name: String, age: Int)
val person = Person("mr complete", 42)
val incompletePersonJson = """{"name":"mr updated"}"""
val update = decode[Person => Person](incompletePersonJson)
然后:
scala> println(update.map(_(person)))
Right(Person(mr updated,42))
我的原创 blog post about this technique uses Argonaut (mostly since I wrote it a couple of months before I started working on circe), and that implementation is available as a library,虽然我从未在任何地方发表过它。
我需要从案例 class 实例(任何需要的 DecodeJson
隐式派生)创建一个更新的实例,给定一个不完整的 json(某些字段缺失)。如何使用 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,然后将其转换为无形 LabelledGeneric
,然后以某种方式使用无形更新来更新大小写 class实例。
编辑 2
阅读 Shapeless 源代码后,我发现我可以生成自己的 "Default"-object。我设法创建了一个解决方案,该解决方案要求在解析 json 时存在案例 class 的实例。我希望避免这种情况,而是稍后提供实例。不管怎样,它是:
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)
。
您可以在 Person
上生成带有宏注释的那些 implicit val defs / pd
(例如,在 object Person
中,并执行 import Person._
以召唤隐式)。有关使用示例,请参阅 this scalameta 中未完成的 Simulacrum(scala-reflect 也很好,但似乎 scalameta 就足够了)。此外,您还必须在某处指定缺少的默认值(42
),例如,如果 class 构造函数(age: Int = 42
,识别也可以在宏中完成)。
为了完整起见:自 0.2 版本以来,已在 circe 中提供了对 "patching" 实例的支持:
import io.circe.jawn.decode, io.circe.generic.auto._
case class Person(name: String, age: Int)
val person = Person("mr complete", 42)
val incompletePersonJson = """{"name":"mr updated"}"""
val update = decode[Person => Person](incompletePersonJson)
然后:
scala> println(update.map(_(person)))
Right(Person(mr updated,42))
我的原创 blog post about this technique uses Argonaut (mostly since I wrote it a couple of months before I started working on circe), and that implementation is available as a library,虽然我从未在任何地方发表过它。