我为我的Java类创建Reads
和Writes
以使用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]
呢?
答案 0 :(得分:1)
由于具体类型在运行时才可用,因此您必须在运行时键入check / parse类型。您可以使用函数语法api来完成它,但我已经使用了实际的实现这些情况的读/写/格式,这些都是这样的:
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")
}
}
}
通过这种方式,您仍然可以为具体类型创建可重用的格式/读/写,您可以在 编译时知道您正在序列化/反序列化的对象。< / p>
答案 1 :(得分:0)
由于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
}
}