【问题标题】:Deserializing Json array into Scala object将 Json 数组反序列化为 Scala 对象
【发布时间】:2011-12-19 11:46:25
【问题描述】:

我在尝试将 JSON 数组反序列化为 Scala 对象时遇到了重大问题

      [{"name":"Cool","city":"College Park","address":"806","id":1},{"name":"Mars ","city":"Durham","address":"12","id":2},{"name":"Something","city":"Raleigh 
","address":"","id":3},{"name":"test","city":"","address":"","id":5}]

我尝试过 gson、jerkson(jackson scala wrapper)、sjson、flexjson。他们都没有工作。我这里有一份客户名单。列出[客户]。

这是我得到的最接近的:

val array = new JsonParser().parse( customers ).getAsJsonArray()

这给了我 4 个数组。它显然没有给我一个客户对象。我试过杰克森。

val array = parse[List[Customer]](customers)

但我明白了。

GenericSignatureFormatError occured : null

我只是想找到一种简单的方法,就像在 Java 中一样。

这是我的 Scala 课程。

    case class Customer(
    id : Pk[ Int ],
    name : String,
    address : Option[ String ],
    city : Option[ String ],
    state : Option[ String ],
    user_id : Int )

    object Customer extends Magic[ Customer ]( Option( "Customer" ) ) { 

    def apply( name : String, address : String, city : String, state : String, user_id : Int ) = {
        new Customer( NotAssigned, name, Some( address ), Some( city ), Some( state ), user_id )
    }

    def delete( id : Int ) = {
        SQL( "DELETE from Customer where id = {id}" ).onParams( id ).executeUpdate()
    }

}

感谢您的帮助。

【问题讨论】:

    标签: json scala playframework gson jackson


    【解决方案1】:

    使用 gson,您可以编写自己的 json 阅读器:

    case class Customer(id: Int, name: String, address: Option[String], 
      city: Option[String], state: Option[String], user_id: Int)
    
    object CustomerJsonReader {
    
       def read(in: Reader) = readCustomers(new JsonReader(in))
    
       def readCustomers(reader: JsonReader) = {
         val customers = new ListBuffer[Customer]
         reader.beginArray()
         while (reader.hasNext()) {
           customers += readCustomer(reader)
         }
         reader.endArray()
         customers toList
       }
    
       def readCustomer(reader: JsonReader): Customer = {
         var id = 0
         var customerName = ""
         var address: Option[String] = None
         var city: Option[String] = None
         var state: Option[String] = None
         var userId = 0
    
         reader.beginObject()
         while (reader.hasNext()) {
           val name = reader.nextName()
           name match {
             case "id" => id = reader.nextInt()
             case "address" => address = Some(reader.nextString())
             case "state" => state = Some(reader.nextString())
             case "user_id" => userId = reader.nextInt()
             case "name" => customerName = reader.nextString()
             case "city" => city = Some(reader.nextString())
             case _ => reader.skipValue()
           }
         }
         reader.endObject()
         Customer(id, customerName, address, city, state, userId)
       }
    
    }
    
    val json = 
      """
      [{"name":"Cool","city":"College Park","address":"806","id":1},
      {"name":"Mars ","city":"Durham","address":"12","id":2},
      {"name":"Something","city":"Raleigh  ","address":"","id":3},
      {"name":"test","city":"","address":"","id":5}] 
      """
    
    val customers: List[Customer] = 
      CustomerJsonReader.read(new StringReader(json))
    

    【讨论】:

    • 这也是一个很好的答案。虽然这对于大型对象可能无法维护。
    • 你是对的,但它提供了很大的控制权来映射到我们想要的任何类型。
    • 同时,在栅栏的 Groovy 一侧,执行“def foo = new Foo(bar:1, baz:'hey') as JSON”,您就有了对象的 JSON 表示。 Scala 真的非常需要这种简洁的 scala 对象到 JSON 的转换。无法获取任意复杂的对象图并轻松序列化为 JSON 使得 Scala REST 成为 PITA。也许 lift-json 或 Jerkson(维护者显然是 awol,顺便说一句)可以做到这一点,但无论如何,尾巴都会摇摆不定;如果在 1 行中定义了案例类,为什么将其转换为 JSON 需要 20 多行?然后你就有了 30 多个领域类,很有趣...
    【解决方案2】:

    我知道使用 gson,您需要 Array 而不是 scala.List。我建议试一试。我认为你应该将它与 gson.fromJson 一起使用。

    【讨论】:

    • 您好,感谢您的回答。这实际上让我更进一步。问题是 gson 不知道如何反序列化 Pk 对象。谢谢。
    • 是的,gson 不能很好地处理 scala 特定的声明。 Id 是一个带参数的案例类,这些都不能用 gson 很好地处理。您可以忽略 id 字段(标记为瞬态)还是在序列化输出中肯定需要它?我想 sjson 在处理 scala 方面应该会好得多(虽然我没有亲自使用过)。
    • 如果 Gson 不能很好地处理 Scala,也许要求 Gson 作者添加支持(或尝试贡献扩展)是有意义的?同时使用与 Scala 兼容的东西(有多个替代建议)
    【解决方案3】:

    你也可以试试 Jerkson = Jackson + Scala
    即使我遇到包含“-”的特殊 JSON 字段的问题,也很容易使用
    最近在推特上看到的一个小tuto:http://logician.free.fr/index.php/2011/09/16/play-scala-and-json/

    【讨论】:

    • 此时建议不要这样做,因为库已切换到 Jackson 2 并且 Jerkson 尚未升级。注释会发生冲突。
    【解决方案4】:

    我现在被这件事逼疯了,尝试了 GSON、Lift-Json、Sjson,最后尝试了Jerkson,并与那个人和平相处。

    这是我将它与 Play 结合使用的方法:

    http://logician.eu/index.php/2011/09/16/play-scala-and-json/

    http://logician.eu/index.php/2011/11/01/writing-custom-deserializers-for-jerkson/

    【讨论】:

      【解决方案5】:

      为此,我使用 Lift 的 json library,它可以轻松地让您解析 JSON 并将值提取到案例类中。它被打包为一个单独的 jar,因此您不需要整个提升框架来使用它。

      import net.liftweb.json._
      import net.liftweb.json.JsonDSL._
      
      implicit val formats = DefaultFormats
      
      val json: String = "[{...."
      val parsed: JValue = parse(json)
      val customers: List[Customer] = parsed.extract[List[Customer]]
      

      只需确保使用 Option 在案例类中定义了任何可选字段。我注意到在您的代码中,对象缺少 user_id 字段,如果将 user_id 字段声明为 Int 而不是 Option[Int],则会导致解析错误。

      【讨论】:

      • 感谢您的建议。我认为根本问题是这些库都不知道如何从 Anorm 反序列化 Pk 对象。你知道吗?谢谢。
      • 我不知道 Pk 对象到底是什么,但您可以通过创建一个类似于 implicit def int2Pk(i: Int): PK[Int] = ...implicit conversion function 来绕过它。 Scala 将在编译时使用该函数来自动处理转换。
      【解决方案6】:

      除了尝试制作 Jerkson(据我所知,这是一个很棒的库),您还可以尝试 Jackson 的 Scala module - 模块是 Jackson 扩展以处理第 3 方数据类型的官方方式作为其他 JVM 语言的本机数据类型和结构。 (这并不是说这比 Jerkson 更官方,只是说有很多有用的 Jackson 扩展模块很多开发者并不熟悉)

      关于 Scala 模块的问题在主要的 Jackson 邮件列表 (user@jackson.codehaus.org) 上进行了讨论;您可能已经找到了可以修复的边缘情况。

      【讨论】:

        【解决方案7】:

        我编写了一个解析器/验证器 dsl,它允许您明确解决任何类型擦除问题。它开箱即用地处理案例类、元组、Option、Either、List、Map、joda DatetTime、管道到函数、多键映射和键名重新映射。

        它使用 Jackson 解析器

        https://github.com/HigherState/jameson

        【讨论】:

          【解决方案8】:

          使用 scala 和 play 库和代码非常简单

          import play.api.libs.json.{Format, Json}
          case class Customer(name:String, city:String, address:String, id:Int)
          object Customer {
             implicit val jsonFormat: Format[Customer] = Json.format(Customer)
          }
          
          val jsonDef = Json.parse(<json-string>)
          val customers = jsonDef.as[List[Customer]]
          

          customersCustomer 对象的列表。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-09-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多