本文介绍了为抽象类创建Read [T]和Write [T]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的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 type.可以使用功能性语法api来做到这一点,但是我已经针对这些情况实际采用了Reads/Writes/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") 
    }
  }
}

通过这种方式,您仍可以为具体类型创建可重用的格式/读取/写入,以便在编译时知道要进行序列化/反序列化的对象的类型. /p>

I'm creating Reads and Writes for my Java classes to make use of the Play Framework's JSON library.

One of my classes has an abstract class field.

ConcreteObj.java

public class ConcreteObj {

private AbstractObj someField;

public ConcreteObj(AbstractObj someField) {
   this.someField = someField;
}

public AbstractObj getSomeField() { return this.someField };

...

Reads & Writes

  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}

However the next step, creating a Reads[AbstractObj], doesn't make sense to me since an abstract class cannot be instantiated.

I suppose that the Writes[AbstractObj] would look like:

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

But what about the Reads[AbstractObj]?

解决方案

Since the concrete type is not available until runtime you will have to type check/parse type at runtime. It is possible you can do it with the functional syntax api but I've resorted to actually implementing Reads/Writes/Format for those cases, something along the lines:

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

This way you can still create re-usable formats/reads/writes for the concrete types that you can use where you do know at compile time what kind of object you are serializing/deserializing.

这篇关于为抽象类创建Read [T]和Write [T]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-22 05:57