Drew H
Drew H

Reputation: 4739

Deserializing Json array into Scala object

I have been having major problems trying to deserialize a JSON array to a Scala object

      [{"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}]

I have tried gson, jerkson(jackson scala wrapper), sjson, flexjson. None of them have worked. What I have here is a List of Customers. List[Customer].

This is the closest I've got:

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

This gave me an 4 arrays. It obviously didn't give me a customer object though. I tried Jerkson.

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

But I get this.

GenericSignatureFormatError occured : null

I'm just trying to find a simple way like I would in Java.

Here is my Scala class.

    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()
    }

}

Thanks for any help.

Upvotes: 4

Views: 8357

Answers (8)

Jai Prakash
Jai Prakash

Reputation: 2759

Its pretty simple to with scala and with play libraries and the code

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]]

customers is list of Customer objects.

Upvotes: 0

J Pullar
J Pullar

Reputation: 1935

I have written a parser/validator dsl, which allows you to explicitly resolve any type erasure issue. Out of the box it handles case classes, tuples, Option, Either, List, Map, joda DatetTime, piping to functions, multiple key mapping and key name remapping.

It uses the Jackson parser

https://github.com/HigherState/jameson

Upvotes: 0

StaxMan
StaxMan

Reputation: 116472

Aside from trying to make Jerkson (which is a great library to use from what I have heard), you could also try Jackson's Scala module -- modules are the official way Jackson is extended to deal with 3rd party datatypes as well as native datatypes and constructs of other JVM languages. (this is not to say this is more official than Jerkson, just that there are many useful Jackson extension modules that many developers are not familiar with)

Issues with Scala module are discussed on main Jackson mailing lists ([email protected]); you may have found an edge case that could be fixed.

Upvotes: 1

Manuel Bernhardt
Manuel Bernhardt

Reputation: 3144

I've been driven insane by this now and went through trying GSON, Lift-Json, Sjson and finally Jerkson, and found peace with that one.

Here's how I use it in combination with 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/

Upvotes: 2

mandubian
mandubian

Reputation: 4427

You can also try Jerkson = Jackson + Scala
Quite easy to use even if I had problems with special JSON fields containing "-"
A small tuto I saw on twitter recently: http://logician.free.fr/index.php/2011/09/16/play-scala-and-json/

Upvotes: 3

Marimuthu Madasamy
Marimuthu Madasamy

Reputation: 13531

With gson, you could write your own json reader:

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))

Upvotes: 4

Dan Simon
Dan Simon

Reputation: 13117

I use Lift's json library for this purpose, it easily lets you parse JSON and extract values into case classes. It's packaged as a separate jar so you don't need the whole lift framework to use it.

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]]

Just make sure any optional fields are defined in the case class using Option. I noticed in your code the objects are missing the user_id field, which would cause a parse error if the user_id field is declared as Int instead of Option[Int].

Upvotes: 1

aishwarya
aishwarya

Reputation: 1976

I know that with gson, you would need Array instead of a scala.List. I would suggest giving that a shot. You should use that with gson.fromJson, I think.

Upvotes: 3

Related Questions