【问题标题】:Encoding nested classes using scala argonaut使用 scala argonaut 编码嵌套类
【发布时间】:2014-03-27 00:10:36
【问题描述】:

我正在尝试对以下案例类进行编码/解码

case class Person(name: String, age: Int, childs: List[Person])

使用以下代码:

object Person {
    implicit def PersonCodecJson =
        casecodec3(Person.apply, Person.unapply)("name", "age", "childs")

}

使用 argonaut,但出现以下编译器错误:

could not find implicit value for evidence parameter of type argonaut.EncodeJson[List[Person]]

显然,编译器不知道如何处理 List[Person] 的编码,因为它在如何编码 Person 的定义中使用。

有没有聪明的方法告诉 argonaut 如何正确编码?

更新:感谢 Travis:现在正在编译,但无法正常工作。

implicit def PersonCodecJson : CodecJson[Person] =
        casecodec3(Person.apply, Person.unapply)("name", "age", "childs")

导致无限递归和试图解码的堆栈溢出

val input = """
    [{"name": "parent1", "age": 31, "childs": [{"name": "child1", "age": 2, "childs": []}]},
     {"name": "parent2", "age": 29, "childs": []}
    ]
    """
val persons = input.decodeOption[List[Person]].getOrElse(Nil)

结果

at Person$.PersonCodecJson(main.scala:8)
at Person$.PersonCodecJson(main.scala:8)
at Person$.PersonCodecJson(main.scala:8)
at Person$.PersonCodecJson(main.scala:8)
at Person$.PersonCodecJson(main.scala:8)
at Person$.PersonCodecJson(main.scala:8)
at Person$.PersonCodecJson(main.scala:8)
at Person$.PersonCodecJson(main.scala:8)
[debug]     Thread run-main-1 exited.
[debug] Interrupting remaining threads (should be all daemons).
[debug] Sandboxed run complete..
java.lang.RuntimeException: Nonzero exit code: 1
at scala.sys.package$.error(package.scala:27)
at sbt.BuildCommon$$anonfun$toError$1.apply(Defaults.scala:1653)
at sbt.BuildCommon$$anonfun$toError$1.apply(Defaults.scala:1653)
at scala.Option.foreach(Option.scala:236)
at sbt.BuildCommon$class.toError(Defaults.scala:1653)
at sbt.Defaults$.toError(Defaults.scala:35)
at sbt.Defaults$$anonfun$runTask$1$$anonfun$apply$36$$anonfun$apply$37.apply(Defaults.scala:656)
at sbt.Defaults$$anonfun$runTask$1$$anonfun$apply$36$$anonfun$apply$37.apply(Defaults.scala:654)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
at sbt.std.Transform$$anon$4.work(System.scala:64)

这种解码嵌套 json 的方法是否有效?我必须以完全不同的方式解决它吗?还是只是又少了一小段代码?

【问题讨论】:

    标签: scala argonaut


    【解决方案1】:

    你已经很接近了——你只需要明确指定类型:

    object Person {
      implicit def PersonCodecJson: CodecJson[Person] =
        casecodec3(Person.apply, Person.unapply)("name", "age", "childs")
    }
    

    就像 Scala 不允许您编写没有显式结果类型的递归方法一样,它不会在没有明确结果类型的情况下找到定义中的隐式定义。

    不确定这有多聪明,但它确实有效。

    【讨论】:

    • 谢谢特拉维斯!它现在正在编译,但仍然无法正常工作。在尝试解码嵌套结构时,我正面临堆栈溢出。我相应地更新了我的问题。
    • 哦,对了。 Play 的 JSON 库为这种情况提供了 lazyRead 方法,但我不确定 Argonaut 中是否有任何可比性。可能值得在邮件列表或 GitHub 上提问。
    【解决方案2】:

    显然问题出在casecodec。如果您手动创建解码器,它可以工作:

    implicit def PersonDecodeJson: DecodeJson[Person] =
        DecodeJson(c => for {
          name <- (c --\ "name").as[String]
          age <- (c --\ "age").as[Int]
          childs <- (c --\ "childs").as[List[Person]]
        } yield Person(name, age, childs)) 
    
    
    val persons = input.decodeOption[List[Person]].getOrElse(Nil)
    //> persons  : List[Person] = List(Person(parent1,31,List(Person(child1,2,List()))), Person(parent2,29,List()))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多