简体   繁体   English

使用Json4s将JSON元组的列表表示为case类字段

[英]Representing a list of JSON tuples as a case class field, with Json4s

Given the following JSON: 给定以下JSON:

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

what's the best way to represent it as a Scala case class? 将其表示为Scala案例类的最佳方法是什么? Logically it seems as though it should be something like: 逻辑上似乎应该是这样的:

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

However, when I try to parse this with Json4s and Jackson, I get: 但是,当我尝试用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

Going the other direction, if I construct my expected Foo ... 如果我构建预期的Foo ,则朝另一个方向前进...

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

...and write it as JSON, I don't get my list of tuples, I get: ...并将其写为JSON,我没有得到元组列表,得到:

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

I see in this answer that despite Json4s claims to produce objects from Tuple2s in the DSL, it can't actually do it for an object field unless that object field is defined as a JValue . 我在这个答案中看到,尽管Json4s 声称可以从DSL中的Tuple2s中产生对象,但是除非该对象字段被定义为JValue否则它实际上不能对一个对象字段进行JValue Since I want to do other things with my Foo model object besides serialize and deserialize it, I don't particularly want to define it in terms of JValues . 由于除了序列化和反序列化之外,我还想对Foo模型对象执行其他操作,因此我特别不想根据JValues定义它。

Given that, what should I be doing, here? 鉴于此,我应该在这里做什么?

I see at least two options how to handle this: 我看到至少两个选择如何处理此问题:

  1. Use a List of Map 使用地图清单
  2. Write a custom conversion function between (String, String) and JObject(JField( , JString( )) 在(String,String)和JObject(JField( ,JString( ))之间编写自定义转换函数

Sometimes it is also useful working directly on the AST or extracting a plain Map[String, Any] via the values function. 有时,直接在AST上运行或通过values函数提取纯Map [String,Any]也很有用。 The Tuple2 conversion is valid as long as you are working with the JValue DSL, but not when doing extraction to/decomposition from Scala types. 只要您正在使用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)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM