如何使用lift-json对scala向量反序列化json数组?
例如:
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)))))
结果是:
{
"type":"Foo",
"bar":[{
"type":"Bar1",
"value":1
},{
"type":"Bar2",
"value":5
},{
"type":"Bar1",
"value":1
}]
}
好。但是当我尝试反序列化这个字符串时
println(Serialization.read[Foo](Serialization.writePretty(Foo(Vector(Bar1(1), Bar2(5), Bar1(1))))))
我得到一个例外:
net.liftweb.json.MappingException:解析的JSON值不匹配 with class constructor args = List(Bar1(1),Bar2(5),Bar1(1))arg types = scala.collection.immutable。$冒号$冒号构造函数= public test.Foo(scala.collection.immutable.Vector)
这意味着json数组与scala列表相关联,而不是在类Foo中定义的矢量类型。我知道有一种方法可以通过扩展net.liftweb.json.Serializer来创建自定义序列化程序,并将其包含在格式值中。但是我如何恢复存储在Vector中的对象类型。我想得到像这样反序列化的结果:
Foo(Vector(Bar1(1),Bar2(5),Bar1(1)))
答案 0 :(得分:3)
我经常对以List
为中心的Lift感到恼火,并且发现自己过去需要做类似的事情。以下是我使用的方法,为您的示例进行了一些调整:
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.")
}
}
}
}
有点难看,可能会被清理一下,但它确实有用。
答案 1 :(得分:1)
您可以添加隐式转化:
implicit def listToVect(list:List[Bar]):Vector[Bar] = list.map(identity)(breakOut)
之后,Serialization.read[Foo]
按预期工作。