Vector deserialization using lift-json

How can I deserialize a json array using lift-json for scala vector?

For instance:

case class Foo(bar: Vector[Bar]) trait Bar { def value: Int } case class Bar1(value: Int) extends Bar case class Bar2(value: Int) extends Bar import net.liftweb.json.{ShortTypeHints, Serialization, DefaultFormats} implicit val formats = new DefaultFormats { override val typeHintFieldName = "type" override val typeHints = ShortTypeHints(List(classOf[Foo],classOf[Bar1],classOf[Bar2])) } println(Serialization.writePretty(Foo(Vector(Bar1(1), Bar2(5), Bar1(1))))) 

Result:

 { "type":"Foo", "bar":[{ "type":"Bar1", "value":1 },{ "type":"Bar2", "value":5 },{ "type":"Bar1", "value":1 }] } 

Good. But when I try to deserialize this line

 println(Serialization.read[Foo](Serialization.writePretty(Foo(Vector(Bar1(1), Bar2(5), Bar1(1)))))) 

I get an exception:

net.liftweb.json.MappingException: The developed JSON values ​​do not match the class constructor args = List (Bar1 (1), Bar2 (5), Bar1 (1)) arg types = scala.collection.immutable. $ colon $ colon constructor = public test.Foo (scala.collection.immutable.Vector)

This means that the json array is associated with the scala list, and not with the vector type defined in the Foo class. I know there is a way to create my own serializer by extending net.liftweb.json.Serializer and including it in the value format. But how can I recover the type of objects that are stored in Vector. I want to get the result of deserialization as follows:

Foo (Vector (Bar1 (1), Bar2 (5), Bar1 (1)))

+4
source share
2 answers

I was often annoyed by the List centricity of Lift, and I needed to do such things in the past. The following is the approach I used, a bit adapted for your example:

 trait Bar { def value: Int } case class Bar1(value: Int) extends Bar case class Bar2(value: Int) extends Bar case class Foo(bar: Vector[Bar]) import net.liftweb.json._ implicit val formats = new DefaultFormats { outer => override val typeHintFieldName = "type" override val typeHints = ShortTypeHints(classOf[Bar1] :: classOf[Bar2] :: Nil) + new ShortTypeHints(classOf[Foo] :: Nil) { val FooName = this.hintFor(classOf[Foo]) override def deserialize = { case (FooName, foo) => foo \ "bar" match { case JArray(bars) => Foo( bars.map(_.extract[Bar](outer, manifest[Bar]))(collection.breakOut) ) case _ => throw new RuntimeException("Not really a Foo.") } } } } 

The view is ugly and could have been cleaned up a bit, but it works.

+3
source

You can add an implicit conversion:

 implicit def listToVect(list:List[Bar]):Vector[Bar] = list.map(identity)(breakOut) 

after that Serialization.read[Foo] works as expected.

+1
source

All Articles