json4s:跨域提取
json4s: cross field extraction
json4s extract
基于 DefaultFormats
和 CustomSerializer
.
中定义的每种类型规则的 JsonAST
有时候想跨场提取。例如,给定一个 json 字符串 {"a": 1, "b": 2}
,我想将 b
的值设置为 a+b
。我能做到:
import org.json4s._
import org.json4s.native.JsonMethods._
import org.json4s.JsonAST._
case class A(a: Int, b: Int)
case object ACustomSerializer extends CustomSerializer[A](
format =>
({
case jo: JObject =>
val a = (jo \ "a").extract[Int]
val b = (jo \ "b").extract[Int] + a
A(a, b)
}, Map())
)
implicit val formats = DefaultFormats + ACustomSerializer
parse("""{"a": 1, "b": 2}""").extract[A] // A(1,3)
但是,如果 case class A
有很多其他字段,则很难为所有字段编写规则。
case class A(a: Int, b: Int, c: Int, d: Int)
case object ACustomSerializer extends CustomSerializer[A](
format =>
({
case jo: JObject =>
val a = (jo \ "a").extract[Int]
val b = (jo \ "b").extract[Int] + a
val c = ...
val d = ...
A(a, b, c, d)
}, Map())
)
如果我们不希望字段 b
有 "cross field extraction",它们本可以由 DefaultFormats
或其他 CustomSerializer
处理。如果案例 class 实际上很大,情况会变得更糟。
有没有办法只为特殊字段编写规则,而让 DefaultFormats
或 CustomSerialzer
处理其余部分?
一般来说,最好按原样解析数据,然后再进行处理(为了维护separation of concerns)。
在这种情况下,它看起来像这样:
val a = parse("""{"a": 1, "b": 2}""").extract[A] // A(1,2)
a.copy(b = a.a + a.b) // A(1,3)
在更复杂的情况下,已处理数据的布局将不同于已解析数据,因此您需要第二个 case class
来描述原始数据和将其转换为已处理格式的函数。虽然这看起来很麻烦,但它会使代码更容易理解并且更易于修改。
json4s extract
基于 DefaultFormats
和 CustomSerializer
.
有时候想跨场提取。例如,给定一个 json 字符串 {"a": 1, "b": 2}
,我想将 b
的值设置为 a+b
。我能做到:
import org.json4s._
import org.json4s.native.JsonMethods._
import org.json4s.JsonAST._
case class A(a: Int, b: Int)
case object ACustomSerializer extends CustomSerializer[A](
format =>
({
case jo: JObject =>
val a = (jo \ "a").extract[Int]
val b = (jo \ "b").extract[Int] + a
A(a, b)
}, Map())
)
implicit val formats = DefaultFormats + ACustomSerializer
parse("""{"a": 1, "b": 2}""").extract[A] // A(1,3)
但是,如果 case class A
有很多其他字段,则很难为所有字段编写规则。
case class A(a: Int, b: Int, c: Int, d: Int)
case object ACustomSerializer extends CustomSerializer[A](
format =>
({
case jo: JObject =>
val a = (jo \ "a").extract[Int]
val b = (jo \ "b").extract[Int] + a
val c = ...
val d = ...
A(a, b, c, d)
}, Map())
)
如果我们不希望字段 b
有 "cross field extraction",它们本可以由 DefaultFormats
或其他 CustomSerializer
处理。如果案例 class 实际上很大,情况会变得更糟。
有没有办法只为特殊字段编写规则,而让 DefaultFormats
或 CustomSerialzer
处理其余部分?
一般来说,最好按原样解析数据,然后再进行处理(为了维护separation of concerns)。
在这种情况下,它看起来像这样:
val a = parse("""{"a": 1, "b": 2}""").extract[A] // A(1,2)
a.copy(b = a.a + a.b) // A(1,3)
在更复杂的情况下,已处理数据的布局将不同于已解析数据,因此您需要第二个 case class
来描述原始数据和将其转换为已处理格式的函数。虽然这看起来很麻烦,但它会使代码更容易理解并且更易于修改。