为抽象类创建Read 和Write

我正在为我的Java类创建ReadsWrites以使用Play Framework的JSON库。

我的一个类有一个抽象类字段。

ConcreteObj.java

 public class ConcreteObj { private AbstractObj someField; public ConcreteObj(AbstractObj someField) { this.someField = someField; } public AbstractObj getSomeField() { return this.someField }; 

读写

  implicit val ConcreteObjReads: Reads[ConcreteObj] = (JsPath \ "someField").read[AbstractObj].map{x: AbstractObj => new ConcreteObj(x)} implicit val ConcreteObjWrites: Writes[ConcreteObj] = (JsPath \ "someField").write[AbstractObj].contramap{x: ConcreteObj => x.getField} 

然而,下一步,创建一个Reads[AbstractObj] ,对我来说没有意义,因为抽象类无法实例化。

我认为Writes[AbstractObj]看起来像:

 implicit val AbstractObjWrites: Writes[AbstractObj] = (JsPath \ "otherField").write[String].contramap{x: AbstractObj => x.getOtherField} 

但是Reads[AbstractObj]怎么样?

由于具体类型在运行时才可用,因此您必须在运行时键入check / parse类型。 您可以使用函数语法api来实现它,但是我已经使用了实际的实现Read / Write / Format这些情况,有些事情是这样的:

 implicit object Example extends Reads[AbstractThing] { def reads(json: JsValue) = { // somehow figure out the concrete subclass of AbstractThing // based on the json (json \ "type").as[String] match { case "type1" => Json.fromJson[Concrete1](json) case "type2" => Json.fromJson[Concrete2](json) case t => JsError(s"Unknown concrete type of AbstractThing: $t") } } } 

这样,您仍然可以为具体类型创建可重用的格式/读/写,您可以在编译时知道您正在序列化/反序列化的对象。

由于ConcreteObj的实现将适用于AbstractObj任何实现,我猜你可以这样做:

 implicit val ConcreteObjReads: Reads[ConcreteObj] = (JsPath \ "someField").read[AbstractObj].map { x: AbstractObj => new ConcreteObj(x) } // I don't know the structure of AbstractObj, but this should give you an idea implicit val AbstractObjReads: Reads[AbstractObj] = (JsPath \ "field").read[String].map{ s: String => new AbstractObject { val field = s } }