Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lift Framework can't deserialize JSON data

I'm trying to deserialize JSON text using the Lift framework, and it doesn't appear that they support Seq trait (although List is supported). As an example...

Some JSON data representing employees (with first and last name)...

{"employees":[{"fname":"Bob","lname":"Hope"},{"fname":"Bob","lname":"Smith"}]}

Here's the employee domain-objects:

case class Employee(fname: String, lname: String) { }
case class Employees(employees: Seq[Employee]) { }

And here's my JSON deserialization code...

class EmployeeTest { 

  @Test def test() {
     val jsonText: String = ....
     val e = deserialize(jsonText)
  }

  def deserialize(in: String): Employees = {
    implicit val formats = net.liftweb.json.DefaultFormats
    net.liftweb.json.Serialization.read[Employees](in)
  }
}

If I change the Employees domain object to use List instead of Seq, then it works. But I'd really like to use Seq if I could.

Here's the exception I see when I run the above code (using Seq): Is there anything I can do to get this to work? Thanks for your help!

net.liftweb.json.MappingException: unknown error
    at net.liftweb.json.Extraction$.extract(Extraction.scala:43)
    at net.liftweb.json.JsonAST$JValue.extract(JsonAST.scala:288)
    at net.liftweb.json.Serialization$.read(Serialization.scala:50)
    at EmployeeTest.deserialize(EmployeeTest.scala:20)   
    at EmployeeTest.test(EmployeeTest.scala:13)
Caused by: java.lang.UnsupportedOperationException: tail of empty list
    at scala.collection.immutable.Nil$.tail(List.scala:388)
    at scala.collection.immutable.Nil$.tail(List.scala:383)
    at net.liftweb.json.Meta$Constructor.bestMatching(Meta.scala:60)
    at net.liftweb.json.Extraction$.findBestConstructor$1(Extraction.scala:187)
    at net.liftweb.json.Extraction$.instantiate$1(Extraction.scala:192)
    at net.liftweb.json.Extraction$.newInstance$1(Extraction.scala:222)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:240)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:269)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:242)
    at net.liftweb.json.Extraction$$anonfun$4.apply(Extraction.scala:194)
    at net.liftweb.json.Extraction$$anonfun$4.apply(Extraction.scala:194)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:206)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:206)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:206)
    at scala.collection.immutable.List.map(List.scala:45)
    at net.liftweb.json.Extraction$.instantiate$1(Extraction.scala:194)
    at net.liftweb.json.Extraction$.newInstance$1(Extraction.scala:222)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:240)
    at net.liftweb.json.Extraction$.extract(Extraction.scala:284)
    at net.liftweb.json.Extraction$.extract0(Extraction.scala:172)
    at net.liftweb.json.Extraction$.extract(Extraction.scala:40)
    ... 33 more
like image 893
shj Avatar asked Nov 06 '10 21:11

shj


1 Answers

Seq is not supported in serialization because it is not a concrete type. During deserialization there's no type information which can be used to decide on concrete implementation. We could use for instance List as a default implementation but then the following property would no longer hold for all types:

deserialize(serialize(x)) == x

This specific case can be deserialized as follows:

import net.liftweb.json._
import net.liftweb.json.JsonAST._

case class Employee(fname: String, lname: String)
case class Employees(employees: Seq[Employee])

object Test extends Application {
  implicit val formats = DefaultFormats
  val s = """ {"employees":[{"fname":"Bob","lname":"Hope"},{"fname":"Bob","lname":"Smith"}]} """

  val json = JsonParser.parse(s)
  val employees = Employees(for {
    JArray(emps) <- json \ "employees"
    emp <- emps
  } yield emp.extract[Employee])

  println(employees)
}
like image 144
Joni Avatar answered Sep 29 '22 12:09

Joni