2

给定以下 JSON:

{
    "foo": "bar",
    "baz":[
        { "qux" : "quux" },
        { "quuux" : "quuuux" }
    ]
}

将其表示为 Scala 案例类的最佳方式是什么?从逻辑上讲,它似乎应该是这样的:

case class Foo(
  foo: String,
  baz: List[(String, String)]
)

然而,当我尝试用 Json4s 和 Jackson 解析这个时,我得到:

No usable value for baz
No usable value for _1
Did not find value which can be converted into java.lang.String
org.json4s.package$MappingException: No usable value for baz
No usable value for _1
Did not find value which can be converted into java.lang.String

走向另一个方向,如果我构建我的预期Foo......

val foo = Foo(foo = "bar", baz = List(("qux" -> "qux1"), ("qux" -> "qux2")))

...并将其写为 JSON,我没有得到我的元组列表,我得到:

{
  "foo" : "bar",
  "baz" : [ {
    "_1" : "qux",
    "_2" : "qux1"
  }, {
    "_1" : "qux",
    "_2" : "qux2"
  } ]
}

我在这个答案中看到,尽管 Json4s声称从 DSL 中生成对象Tuple2s,但它实际上不能为对象字段执行此操作,除非该对象字段被定义为JValue. 因为除了序列化和反序列化之外,我还想对我的模型对象做其他事情,Foo所以我不想特别想用JValues.

鉴于此,我应该在这里做什么?

4

1 回答 1

1

我至少看到两个选项来处理这个问题:

  1. 使用地图列表
  2. 写一个自定义的(String, String)和JObject(JField( , JString( ))之间的转换函数

有时直接在 AST 上工作或通过values函数提取普通的 Map[String, Any] 也很有用。只要您使用 JValue DSL,Tuple2 转换就有效,但在从 Scala 类型提取/分解时无效。

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._

val json = """{
             |    "foo": "bar",
             |    "baz":[
             |        { "qux" : "quux" },
             |        { "quuux" : "quuuux" }
             |    ]
             |}""".stripMargin

class StringTupleSerializer extends CustomSerializer[(String, String)](format => ( {
  case JObject(List(JField(k, JString(v)))) => (k, v)
}, {
  case (s: String, t: String) => (s -> t)
}))

implicit val formats = DefaultFormats + new StringTupleSerializer

case class FooMap(foo: String, baz: List[Map[String, String]])

case class FooTuple(foo: String, baz: List[(String, String)])

val ast = parse(json)

println(ast.extractOpt[FooMap])
//  Some(FooWithMap(bar,List(Map(qux -> quux), Map(quuux -> quuuux))))

println(ast.extractOpt[FooTuple])
//  Some(FooWithTuple(bar,List((qux,quux), (quuux,quuuux))))

val foo1 = FooMap(foo = "bar", baz = List(Map("qux" -> "qux1"), Map("qux" -> "qux2")))
val foo2 = FooTuple(foo = "bar", baz = List(("qux" -> "qux1"), ("qux" -> "qux2")))

println(pretty(Extraction.decompose(foo1)))
println(pretty(Extraction.decompose(foo2)))
于 2014-02-05T01:04:16.860 回答