将Json数组反序列化为Scala对象

将Json数组反序列化为Scala对象,json,scala,playframework,gson,jackson,Json,Scala,Playframework,Gson,Jackson,我在尝试将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"

我在尝试将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(jacksonscala包装器)、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()
    }

}

谢谢您的帮助。

我知道使用gson时,您需要的是数组而不是scala.List。我建议你打一针。我认为,您应该将它与gson.fromJson一起使用。

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

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在case类中定义了任何可选字段。我注意到在您的代码中,对象缺少user\u id字段,如果user\u id字段声明为
Int
,而不是
Option[Int]
,则会导致解析错误。使用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))

您也可以尝试Jerkson=Jackson+Scala
即使我对包含“-”的特殊JSON字段有问题,也很容易使用

我最近在推特上看到一个小图图:

我现在已经被它逼疯了,我尝试了GSON、Lift-Json、Sjson,最后终于找到了和平

以下是我如何将其与游戏结合使用:


除了尝试制作Jerkson(据我所知,这是一个很好的库),您还可以尝试Jackson的——模块是Jackson扩展到处理第三方数据类型以及本机数据类型和其他JVM语言构造的正式方式。 (这并不是说这比Jerkson更正式,只是有许多有用的Jackson扩展模块,许多开发人员并不熟悉)


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

我已经编写了一个解析器/验证器dsl,它允许您显式解决任何类型的擦除问题。开箱即用,它处理大小写类、元组、选项、列表、映射、joda DateTime、管道到函数、多键映射和键名重新映射

它使用Jackson解析器


使用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]]
import play.api.libs.json.{Format,json}
案例类客户(名称:String,城市:String,地址:String,id:Int)
目标客户{
隐式val jsonFormat:Format[Customer]=Json.Format(Customer)
}
val jsonDef=Json.parse()
val customers=jsonDef.as[List[Customer]]

客户
客户
对象的列表。

谢谢您的建议。我认为潜在的问题是这些库都不知道如何从Anorm反序列化Pk对象。知道吗?谢谢。我不知道Pk对象到底是什么,但是你可以通过创建一个类似于
隐式def int2Pk(I:Int):Pk[Int]=…
的东西来绕过它。Scala将在编译时使用该函数自动处理转换。嘿,谢谢你的回答。这实际上让我更进一步了。问题是gson不知道如何反序列化Pk对象。谢谢。是的,gson不能很好地处理特定于scala的声明。Id是一个接受参数的case类,gson不能很好地处理这些参数。您可以忽略id字段(标记为transient),还是在序列化输出中确实需要它?我想sjson应该在处理scala方面做得更好(不过我个人没有使用过)。如果Gson不能很好地处理scala,请Gson的作者添加支持(或者尝试提供支持的扩展)也许是有意义的?同时,使用与Scala一起工作的soemthing(有多个备选建议),这也是一个很好的答案。虽然这对于大型对象来说是不可维护的。你是对的,但是它提供了很多控制来映射到我们想要的任何类型。同时,在Groovy的围栏上,有一个“def foo=new foo(bar:1,baz:'hey')作为JSON”并且你有一个对象的JSON表示。Scala真的,真的需要这种简洁的Scala对象到JSON的转换。无法获取任意复杂的对象图并轻松序列化为JSON,这使得Scala REST成为PITA。也许lift json或Jerkson(维护者显然擅离职守,顺便说一句)可以做到这一点,但不管怎样,尾巴都会摇狗;如果一个case类是在一行中定义的,为什么将它转换成JSON需要20多行呢?然后你有30多个域类,很有趣…现在建议不要使用它,因为库已经切换到Jackson 2,而Jarkson还没有升级。注释将发生冲突。