Scala Play框架2.1派生类

ari*_*ris 7 polymorphism scala playframework-2.1

我想为包含基类和派生类的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))
}
Run Code Online (Sandbox Code Playgroud)

Scala和Play新手在这里,请原谅不当使用的术语.

joh*_*ren 5

json API广泛使用隐式参数,这是Scala的一个特性,您可以在其中提供"隐式"参数列表,如果您不指定这些参数,编译器将尝试在当前作用域中找到标记为隐式的对象.匹配该签名.

所以,如果您举例如下:

implicit val s = "my implicit string"

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

// and then call it
magicPrint
Run Code Online (Sandbox Code Playgroud)

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

magicPrint(s)
Run Code Online (Sandbox Code Playgroud)

编译器在编译时使用隐式参数选择格式/编写器.如果你看一下方法的签名toJson[A](item: A)(implicit writes: Writes[A]),那么它就是一个隐含的Writes[A],在你的情况下是一个,Writes[List[Animal]]因为List[Animal]是你的列表的类型l.Play包含一个默认具有一个编写器,它负责处理collection(DefaultWrites.traversableWrites),而collection 又采用隐式Writes[A]- 在你的情况下Writes[Animal],编译器将选择并传递你的animalWrites.

您的列表包含不同类型的动物是在运行时发生的事情,编译器无法从您可用的类型信息中获知 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")
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这有帮助!