Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating Read[T] and Write[T] for Abstract Class

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]?

like image 691
Kevin Meredith Avatar asked Feb 12 '14 03:02

Kevin Meredith


1 Answers

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.

like image 157
johanandren Avatar answered Sep 17 '22 02:09

johanandren