11

给定一个不完整的 json(缺少某些字段),我需要从一个案例类实例(任何需要DecodeJson的 s 隐式派生)创建一个更新的实例。如何使用 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 update 来更新案例类实例。


编辑 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).

4

2 回答 2

16

为了完整起见:自 0.2 版本以来,大约已提供对此类“修补”实例的支持:

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))

我关于这项技术的原始博客文章使用了 Argonaut(主要是因为我在开始研究 circe 的几个月前编写了它),并且该实现可作为库提供,尽管我从未在任何地方发布过它。

于 2016-09-22T12:42:49.900 回答
3

您可以生成implicit val defs / pd带有宏注释的那些Personobject Person例如,在 中,并import Person._调用隐式)。请参阅scalameta中未完成的 Simulacrum (scala-reflect 也很好,但似乎 scalameta 在这里就足够了)以获取使用示例。您还必须在某处指定缺少的默认值 ( 42),例如,如果类构造函数 ( age: Int = 42,识别也可以在宏中完成)。

于 2016-09-17T19:28:50.650 回答