我正在尝试包装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#。
答案 0 :(得分: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框架而言,您可以查看:
答案 1 :(得分: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
对象已经为许多标准类型定义了解码器,因此对于这些类型,您将没有任何特殊要做。
对于其他类型(例如您的自定义类型),您必须定义解码器并导入它们。