【问题标题】:scala - parse json of more than 22 elements into case classscala - 将超过 22 个元素的 json 解析为案例类
【发布时间】:2015-10-25 19:03:36
【问题描述】:

这个问题或类似的问题之前已经发布过,但是这些解决方案都不再适用于最新的库。经过广泛的搜索,到目前为止,我没有发现最新版本的最流行库 spray-json 或 play-json(或它们的插件)可以处理这种情况。有什么东西可以将超过 22 个元素的 json 解析为 scala 案例类吗?由于 scala 2.11 案例类不再限于 22 个元素。请,只有完全有效的解决方案。下面是明显的 json 示例。

{
    "a": 1,
    "b": 2,
    "c": 3,
    "d": 4,
    "e": 5,
    "f": 6,
    "g": 7,
    "h": 8,
    "i": 9,
    "j": 10,
    "k": 11,
    "l": 12,
    "m": 13,
    "n": 14,
    "o": 15,
    "p": 16,
    "q": 17,
    "r": 18,
    "s": 19,
    "t": 20,
    "u": 21,
    "v": 22,
    "w": 23
}

更新:这是您无法控制 json 结构的情况,例如它是从第 3 方 api 检索的。 twitter 的推文 json 示例:http://pastebin.com/h8fHAsd8

【问题讨论】:

  • 这样的单片案例类实用吗?有哪些用例?
  • @DominykasMostauskis 请看我的更新。

标签: json scala


【解决方案1】:

circe 支持,Shapeless 支持自动编解码器派生。注意,与json4s的case类解码不同,这里没有运行时反射:

case class Foo(
  a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, h: Int, i: Int,
  j: Int, k: Int, l: Int, m: Int, n: Int, o: Int, p: Int, q: Int, r: Int,
  s: Int, t: Int, u: Int, v: Int, w: Int
)

import io.circe.generic.auto._, io.circe.jawn.decode

val json = """{
  "a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, "h": 8, "i": 9,
  "j": 10, "k": 11, "l": 12, "m": 13, "n": 14, "o": 15, "p": 16, "q": 17,
  "r": 18, "s": 19, "t": 20, "u": 21, "v": 22, "w": 23
}"""

val result: cats.data.Xor[io.circe.Error, Foo] = decode[Foo](json)

这是一个最小的build.sbt 文件:

scalaVersion := "2.11.7"

addCompilerPlugin(
  "org.scalamacros" % "paradise" % "2.1.0-M5" cross CrossVersion.full
)

libraryDependencies ++= Seq(
  "io.circe" %% "circe-core" % "0.1.1",
  "io.circe" %% "circe-generic" % "0.1.1",
  "io.circe" %% "circe-jawn" % "0.1.1"
)

即将发布的 0.2.0 版本(目前以快照形式提供)包括对泛型派生的大量改进,但对于像这样的简单示例,0.1.1 的行为是相同的。

【讨论】:

  • 谢谢,这当然很有趣。不过我有一个额外的问题 - 它能够处理嵌套的 json 吗?
  • @Caballero 是的,当然!在 0.1.1 中存在一些嵌套案例类的自动派生失败的极端案例,但它们大多在 0.2.0 中得到修复。
  • 是的,编译器似乎卡住了我试图解析的大量 json,出现错误 diverging implicit expansion for type io.circe.Decoder[Foo] starting with method decodeCaseClass in trait GenericInstances。知道 0.2.0 版什么时候发布吗?
  • @Caballero 我只是在等待 Shapeless 2.3.0 ——我预计会在接下来的几周内发布。 Sonatype 现在有 0.2.0 的快照,我很想知道您是否在它们上遇到同样的错误。
  • 感谢 Caballero 提供的示例,它是 a bug,我正在努力。
【解决方案2】:

对于 play-json,play-json-extensions 提供了一个扩展,支持 >22 个字段和一些其他用例,如序列化密封特征结构、单例对象等。

import org.cvogt.play.json.Jsonx
implicit val jsonFormat = Jsonx.formatCaseClass[Foo] // Instead of Json.format

https://github.com/cvogt/play-json-extensions

circe/argonaut 当然也值得一试。不确定它们与 play-json/play-json-extensions 相比在功能和稳定性方面如何。

【讨论】:

  • 谢谢。我已经尝试过了,但是没有一个明确的示例说明如何将具有 >22 个元素的 json 解析为案例类,并且由于相同的 22 个元素限制问题,play-json 隐式转换不起作用。跨度>
  • 只需将 Jsonx.formatCaseClass 用于您通常使用 Json.format 的 22+ 案例类。其他一切都应该保持不变。还是不行?
  • 这是一个我正在尝试的示例:pastebin.com/HLJK4wWC 我可能做错了什么,但我找不到与此案例相近的明确工作示例。
  • 您缺少 Bar 的 jsonFormat。你需要它,就像在 play-json 中一样。然后事情应该会正常工作。添加了一张票,试图改善错误信息。 github.com/cvogt/play-json-extensions/issues/19
  • 是的,我试过了,但仍然遇到同样的错误加上另一个错误:reference to Json is ambiguous; it is imported twice in the same scope by import _root_.play.api.libs.json._ and import play.libs.Json implicit val barFormat = Jsonx.formatCaseClass[Bar]
【解决方案3】:

受@cvogt 和其他我个人需求的启发,我开发了一个库来通过宏透明地管理 > 22 个字段和其他功能。

图书馆是here和documentation

JsonFormat 注释通过宏创建一个“pimped” json 格式来管理很多东西。

主要特点是:

  • 为 ScalaJS 播放 JSON
  • 适合懒人的 JsonFormat 宏注解
  • 在缺少的 JSON 中填充的默认字段值
  • Play JSON(“key”)的字段重写
  • +22 字段案例类格式化程序和更多 Play Json 扩展
  • 用于 Scala 和 ScalaJS 的 Joda 日期时间
  • Scala 和 ScalaJS 的强类型枚举(字符串和整数)
  • 变体类型

【讨论】:

    【解决方案4】:

    尝试使用json4s:

    scala> import org.json4s._
    import org.json4s._
    
    scala> import org.json4s.native.JsonMethods._
    import org.json4s.native.JsonMethods._
    
    scala> case class Foo(
         |                 a: String,
         |                 b: String,
         |                 c: String,
         |                 d: String,
         |                 e: String,
         |                 f: String,
         |                 g: String,
         |                 h: String,
         |                 i: String,
         |                 j: String,
         |                 k: String,
         |                 l: String,
         |                 m: String,
         |                 n: String,
         |                 o: String,
         |                 p: String,
         |                 q: String,
         |                 r: String,
         |                 s: String,
         |                 t: String,
         |                 u: String,
         |                 v: String,
         |                 w: String
         |                 )
    defined class Foo
    
    scala> 
    
    scala>     implicit val formats = DefaultFormats
    formats: org.json4s.DefaultFormats.type = org.json4s.DefaultFormats$@6eb0a5cb
    
    scala>     val f = parse("{\n    \"a\": 1,\n    \"b\": 2,\n    \"c\": 3,\n    \"d\": 4,\n    \"e\": 5,\n    \"f\": 6,\n    \"g\": 7,\n    \"h\": 8,\n    \"i\": 9,\n    \"j\": 10,\n    \"k\": 11,\n    \"l\": 12,\n    \"m\": 13,\n    \"n\": 14,\n    \"o\": 15,\n    \"p\": 16,\n    \"q\": 17,\n    \"r\": 18,\n    \"s\": 19,\n    \"t\": 20,\n    \"u\": 21,\n    \"v\": 22,\n    \"w\": 23\n}")
               .extract[Foo]
    f: Foo = Foo(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
    

    【讨论】:

      猜你喜欢
      • 2014-06-25
      • 1970-01-01
      • 1970-01-01
      • 2019-01-18
      • 2014-09-03
      • 2021-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多