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
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With