【问题标题】:Scala deserialize JSON to CollectionScala 将 JSON 反序列化为 Collection
【发布时间】:2018-07-02 06:45:31
【问题描述】:

我的 JSON 文件包含以下详细信息 { “类别”:“年龄,性别,邮政编码” }

我的 scala 代码低于一个

val filename = args.head
println(s"Reading ${args.head} ...")
val json = Source.fromFile(filename)
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
val parsedJson = mapper.readValue[Map[String, Any]](json.reader())   
val data = parsedJson.get("category").toSeq

它返回 Seq(Any) = example List(age, gender,post_code) 但我需要 Seq(String) 输出,如果有人对此有任何想法,请帮助我。

【问题讨论】:

    标签: scala scala-collections


    【解决方案1】:

    scala 中的想法是尽可能保证类型安全,您可以使用Map[String, Any] 放弃这一点。

    因此,我建议使用表示您的 JSON 数据的数据类。

    例子,

    定义一个映射器,

    scala> import com.fasterxml.jackson.databind.ObjectMapper
    import com.fasterxml.jackson.databind.ObjectMapper
    
    scala> import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
    import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
    
    scala> import com.fasterxml.jackson.module.scala.DefaultScalaModule
    import com.fasterxml.jackson.module.scala.DefaultScalaModule
    
    scala> val mapper = new ObjectMapper() with ScalaObjectMapper
    mapper: com.fasterxml.jackson.databind.ObjectMapper with com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper = $anon$1@d486a4d
    
    scala> mapper.registerModule(DefaultScalaModule)
    res0: com.fasterxml.jackson.databind.ObjectMapper = $anon$1@d486a4d
    

    现在,当您反序列化为 Map[K, V] 时,您无法指定所有嵌套的数据结构,

    scala> val jsonString = """{"category": ["metal", "metalcore"], "age": 10, "gender": "M", "postCode": "98109"}"""
    jsonString: String = {"category": ["metal", "metalcore"], "age": 10, "gender": "M", "postCode": "98109"}
    
    scala> mapper.readValue[Map[String, Any]](jsonString)
    res2: Map[String,Any] = Map(category -> List(metal, metalcore), age -> 10, gender -> M, postCode -> 98109)
    

    以下是一个解决方案,将一些关键转换为所需的数据结构,但我个人不推荐。

    scala> mapper.readValue[Map[String, Any]](jsonString).get("category").map(_.asInstanceOf[List[String]]).getOrElse(List.empty[String])
    res3: List[String] = List(metal, metalcore)
    

    最好的解决方案是在下面的示例中定义一个我称之为SomeData 的数据类并对其进行反序列化。 SomeData 是根据您的 JSON 数据结构定义的。

    scala> final case class SomeData(category: List[String], age: Int, gender: String, postCode: String)
    defined class SomeData
    
    scala> mapper.readValue[SomeData](jsonString)
    res4: SomeData = SomeData(List(metal, metalcore),10,M,98109)
    
    scala> mapper.readValue[SomeData](jsonString).category
    res5: List[String] = List(metal, metalcore)
    

    【讨论】:

    • 感谢您的建议,但是,在我的情况下,我没有为案例类预定义 JSON,它总是会不断变化。这将是动态值
    • 也有办法。花一些时间学习 scala 中的类型。否则,您可以使用 _.asInstanceOf 更新答案 => .get("category").map(_.asInstanceOf[List[String]]).getOrElse(List.empty[String]) 我不推荐。
    • 上面那个对我来说很完美,你有什么理由不推荐,如果我用会有什么问题?
    【解决方案2】:

    只需将 JSON 读取为 JsonNode,并直接访问该属性:

    val jsonNode = objectMapper.readTree(json.reader())
    val parsedJson = jsonNode.get("category").asText
    

    【讨论】:

      【解决方案3】:
      • 通过使用 scala 通用函数将 JSON 字符串转换为案例类/对象,您可以反序列化为您想要的任何内容。喜欢

        • JSON to Collection,
        • JSON to Case Class
        • JSON to Case Class with Object as field
      • 请找到我使用泛型 here 提供的有效且详细的答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-19
        • 2012-09-17
        • 2015-02-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-30
        相关资源
        最近更新 更多