3

我正在尝试包装 Argonaut ( http://argonaut.io ) 以便在 Scala 项目中序列化/反序列化 JSON。我们以前在哪里使用 Jerkson,但由于它已停产,我们正在寻找替代方案。

这是基本的 JSON 包装器

import argonaut._, Argonaut._

object Json {
  def Parse[T](input: String): T = {
    input.decodeOption[T].get
  }
}

当我尝试编译它时,我收到以下错误。

could not find implicit value for evidence parameter of type argonaut.DecodeJson[T]
    input.decodeOption[T]
                  ^
not enough arguments for method decodeOption: (implicit evidence$6: argonaut.DecodeJson[T]) Option[T].
Unspecified value parameter evidence$6.
    input.decodeOption[T]
                  ^

任何有关如何解决此问题的建议或关于我做错了什么的指针将不胜感激。

也非常欢迎关于替代 JSON 框架的建议。

我对 Scala/Java 以及泛型如何在那里工作有点陌生,但我多年来一直在编写 .NET/C#。

4

2 回答 2

7

为了使您的代码正常工作,您需要Json像这样重新定义对象:

object Json {
  def Parse[T](input: String)(implicit decode:DecodeJson[T]): Option[T] = {
    input.decodeOption[T]
  }
}

您缺少的是函数需要的隐式DecodeJson实例,decodeOption以便弄清楚如何解码。您还需要将返回类型定义为Option[T]而不仅仅是T. 这一切工作的完整示例如下所示:

import argonaut._, Argonaut._
case class User(id:Long, email:String, name:String)

object Json {
  def Parse[T](input: String)(implicit decode:DecodeJson[T]): Option[T] = {
    input.decodeOption[T]
  }
}

object JsonTest{
  implicit val userDecode = casecodec3(User.apply, User.unapply)("id", "email", "name")

  def main(args: Array[String]) {
    val json = """{
      "id": 1,
      "email": "foo@test.com",
      "name": "foo bar"
    }"""

    val userOpt = Json.Parse[User](json)
    println(userOpt)
  }
}

至于其他 Json 框架,您可以查看:

播放 Json

json4s

喷雾-json

杰克逊斯卡拉模块

于 2013-06-11T12:08:50.817 回答
4

似乎 Argonaut 与几乎所有 scala 序列化库一样,使用类型类模式。这听起来很花哨,但实际上它只是意味着在序列化/反序列化类型的对象时T,它需要您隐式传递另一个对象的实例,该对象的部分或全部过程被推迟到。具体来说,当您这样做时decodeOption[T],您需要在范围内拥有一个实例argonaut.DecodeJson[T]decodeOption将在反序列化期间使用)。

您应该做的只是要求将此隐式值传递给Parse(然后它将自动传递给decodeOption

def Parse[T](input: String)(implicit decoder: argonaut.DecodeJson[T]): Option[T] = {
  input.decodeOption[T]
}

Scala 甚至提供了一些语法糖来使声明更短(这称为“上下文绑定”):

def Parse[T:argonaut.DecodeJson](input: String): Option[T] = {
  input.decodeOption[T]
}

现在,在调用 时Parse,您需要在作用域中引入 的隐式值argonaut.DecodeJson,否则调用将无法编译。显然,该Argonaut对象已经为许多标准类型定义了解码器,因此对于这些类型,您无需做任何特别的事情。对于其他类型(例如您的自定义类型),您必须定义解码器并导入它们。

于 2013-06-11T12:07:31.520 回答