使用Argonaut或Circe更新不完整JSON的案例类

时间:2016-09-03 16:02:29

标签: json scala shapeless argonaut circe

我需要从案例类实例(隐式派生所需的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,然后将其转换为Shapeless LabelledGeneric,然后以某种方式使用Shapeless更新来更新case类实例。

修改2

在阅读了Shapeless源代码后,我发现我可以生成自己的“默认”对象。我设法创建了一个解决方案,它需要在解析json时出现case类的实例。我希望避免这种情况,而是稍后提供实例。无论如何它是:

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)

2 个答案:

答案 0 :(得分:15)

为了完整起见:支持&#34;修补&#34;自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))

关于这种技术的原始blog post使用了Argonaut(大部分是因为我在开始编写circe之前几个月写了它),并且该实现是available as a library,尽管我从来没有在任何地方发表。

答案 1 :(得分:3)

您可以在implicit val defs / pd(例如Person中)生成带有宏注释的object Person,然后执行import Person._来召唤暗示。请参阅this scalameta中未完成的Simulacrum(scala-reflect也很好,但看起来scalameta就足够了)作为用法示例。此外,您必须在某处指定缺少的默认值(42),例如,在类构造函数(age: Int = 42中,也可以在宏中完成识别)。