【问题标题】:Vector deserialization by using lift-json使用 lift-json 进行向量反序列化
【发布时间】:2012-06-28 11:53:32
【问题描述】:

如何使用 lift-json 将 json 数组反序列化为 scala 向量?

例如:

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 值不匹配 使用类构造函数 args=List(Bar1(1), Bar2(5), Bar1(1)) arg types=scala.collection.immutable.$colon$colon 构造函数=public test.Foo(scala.collection.immutable.Vector)

这意味着与scala列表关联的json数组,而不是Foo类中定义的向量类型。我知道可以通过扩展 net.liftweb.json.Serializer 来创建自定义序列化程序并将其包含到格式值中。但是我怎样才能恢复存储在 Vector 中的对象类型。我想得到这样的反序列化结果:

Foo(向量(Bar1(1), Bar2(5), Bar1(1)))

【问题讨论】:

    标签: json scala lift lift-json


    【解决方案1】:

    我经常对 Lift 的 List-centricness 感到恼火,并且发现自己过去需要做类似的事情。以下是我使用的方法,针对您的示例进行了一些调整:

    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.")
            }
          }
        }
    }
    

    有点难看,可能会稍微清理一下,但它确实有效。

    【讨论】:

    • 谢谢。对我的例子来说很好。但是如果有很多其他类型的向量,对于所有这些类型,我应该重写反序列化方法吗?那么这个例子呢:case class Bar3(value: Int, bars2: Vector[Bars2]) extends Bar 还有其他更通用的解决方案吗?
    【解决方案2】:

    你可以添加一个隐式转换:

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

    之后,Serialization.read[Foo] 按预期工作。

    【讨论】:

    • 不工作。我认为这种隐式转换必须深入方法读取执行,而不是在这一层。或者你的意思是在哪里插入这段代码?
    • 我在 REPL 上试过了。隐式应该在工作范围内。例如必须在需要它们的类中导入。
    猜你喜欢
    • 2011-06-29
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-26
    相关资源
    最近更新 更多