我正在寻找一个好的抽象来从JSON中提取数据(我现在正在使用json4s
)。
假设我有一个案例类A
和JSON格式的数据。
case class A(a1: String, a2: String, a3: String)
{"a1":"xxx", "a2": "yyy", "a3": "zzz"}
我需要一个函数来提取JSON数据并使用以下数据返回A
:
val a: JValue => A = ...
我不想从头开始编写函数a
。我宁愿从原始函数中编译。
例如,我可以编写一个基本函数来按字段名称提取字符串:
val str: (String, JValue) => String = {(fieldName, jval) => ... }
现在我想从a: JValue => A
撰写函数str
。它有意义吗?
答案 0 :(得分:2)
考虑使用Play-JSON,其中包含composable“读取”对象。如果您曾经使用过ReactiveMongo,它可以以相同的方式使用。与此处的一些较旧的帖子相反,它可以单独使用,而不需要Play的大部分内容。
它使用常见的“隐式翻译”(我的术语)成语。我发现我最喜欢使用它的反序列化模式并没有在文档中突出显示 - 他们所支持的模式很难做到,恕我直言。我大量使用了.as和.asOpt,这些都记录在上面的第一个链接页面的“Using JsValue.as/asOpt”小部分中。反序列化JSON对象时,可以说类似
val person:Person = (someParsedJsonObject \ "aPerson").as[Person]
只要你在范围内有一个隐含的Reads [Person],一切正常。所有原始类型和许多集合类型都有内置的Reads。在许多情况下,将Reads and Writes隐式对象放在伴侣对象中是有意义的,例如Person。
我认为json4s有类似功能,但我可能错了。
答案 1 :(得分:1)
Argonaut是功能齐全的Scala库。
它允许encode/decode case classes(JSON编解码器)。
import argonaut._, Argonaut._
case class Person(name: String, age: Int)
implicit def PersonDecodeJson: DecodeJson[Person]
jdecode2L(Person.apply)("name", "age")
// Codec for Person case class from JSON of form
// { "name": "string", "age": 1 }
它还提供JSON光标(镜头/单片眼镜)进行自定义解析。
implicit def PersonDecodeJson: DecodeJson[Person] =
DecodeJson(c => for {
name <- (c --\ "_name").as[String]
age <- (c --\ "_age").as[String].map(_.toInt)
} yield Person(name, age))
// Decode Person from a JSON with property names different
// from those of the case class, and age passed as string:
// { "_name": "string", "age": "10" }
解析结果由DecodeResult类型表示,可以组成(.map
,.flatMap
)并处理错误情况。