7

我想为包含基类和派生类的 List 生成 JSON。下面的代码只为 Animal 类生成 JSON(我没有得到 Dog 类型成员的品种字段)。一些帮助将不胜感激。

import play.api.libs.json._

class Animal (val name:String) {
}

object Animal {
  implicit object animalWrite extends Writes[Animal] {
    def writes(ts: Animal) = JsObject(Seq("name" -> JsString(ts.name)))
  }
}

case class Dog (override val name:String, val breed: String) 
    extends Animal(name)  {
}

object Dog {
    implicit val format = Json.format[Dog]
}

case class Cat (override val name:String, val hairLength: Int) 
    extends Animal(name)  {
}

object Cat {
    implicit val format = Json.format[Cat]
}

object helloWorld extends App {
//  The list below outputs:     [{"name":"Ruff","breed":"labrador"}]
//  val l = List[Dog](Dog("Ruff", "labrador"))

//  The list below outputs:     [{"name":"Ruff"},{"name":"Fluffy"}]
//  I expect to see: [{"name":"Ruff","breed":"labrador"},{"name":"Fluffy","hairLength":3}]
    val l = List[Animal](Dog("Ruff", "labrador"), Cat("Fluffy", 3))
    println(Json.toJson(l))
}

Scala 和 Play 新手,请原谅术语的不当使用。

4

1 回答 1

5

json API 广泛使用隐式参数,这是 Scala 的一项功能,您可以在其中提供“隐式”参数列表,如果您不指定这些参数,编译器将尝试在当前范围内查找标记为隐式和匹配该签名。

因此,例如,如果您会写:

implicit val s = "my implicit string"

def magicPrint(implicit message: String) { println(message) }

// and then call it
magicPrint

编译器将为参数消息选择 s,因为它在范围内并且具有正确的类型 ( String),因此在隐式解析之后,最后一行代码实际上看起来更像这样

magicPrint(s)

Format/Writer 由编译器在编译时使用隐式参数选择。如果您查看方法的签名toJson[A](item: A)(implicit writes: Writes[A]),它需要一个隐含的Writes[A],在您的情况下是 a,Writes[List[Animal]]因为List[Animal]是您的 list 的类型l。Play 包含一个默认的编写器,该编写器负责处理集合 ( ),而在您的情况下,该集合DefaultWrites.traversableWrites又采用隐式- ,因此编译器将选择并传递您的 animalWrites。Writes[A]Writes[Animal]

您的列表包含不同类型的动物是在运行时发生的事情,编译器无法从您可用的类型信息中知道这一点Json.toJson(l)

因此,正如您所见,您无法以您想的方式实现您想要的,但您可以通过让动物作家了解亚型来以几乎相同的方式做到这一点,例如:

implicit object animalWrite extends Writes[Animal] {
  def writes(ts: Animal) = ts match {
    // this will get an implicit Writes[Dog] since d is a Dog
    case d: Dog => Json.toJson(d) 
    // this will get an implicit Writes[Cat] since c is a Cat
    case c: Cat => Json.toJson(c) 
    case x => throw new RuntimeException(s"Unknown animal $x")
  }
}

希望这有帮助!

于 2013-07-18T20:16:22.507 回答