jsonscalaplayframework-json

What should a Play framework implicit val Writes[T] look like for super type?


What do I put instead of ??? so the code will type check? Or is there something else I should be doing? I'm using Play to generate JSON for classes B, C, D that all extend A (Layer), but the code that tries to build the JSON only knows it has an A, not which subtype B, C or D.

class Layer

object Layer {
  implicit val layerWrites = new Writes[Layer] {
    def writes(x: Layer) = x match {
      case a: CloudLayer         => ???
      case b: VerticalVisibility => ???
      case c: SkyClear           => ???
    }
  }
}

case class CloudLayer(coverage: String, base: Int) extends Layer
case class VerticalVisibility(height: Int)         extends Layer
case class SkyClear()                              extends Layer

object CloudLayer {
  implicit val cloudLayerWrites = new Writes[CloudLayer] {
    def writes(x: CloudLayer) = Json.obj(
      "layerType" -> "cloudLayer",
      "coverage" -> x.cloudCoverage,
      "base" -> x.base * 100
    )
  }
}

object VerticalVisibility {
  implicit val verticalVisibilityWrites = new Writes[VerticalVisibility] {
    def writes(x: VerticalVisibility) = Json.obj(
      "layerType" -> "verticalVisibility",
      "height" -> x.height * 100
    )
  }
}

object SkyClear {
  implicit val skyClearWrites = new Writes[SkyClear] {
    def writes(x: SkyClear) = Json.obj( "layerType" -> "skyClear" )
  }
}

Solution

  • The easiest solution would be just to remove the implicit modifiers from the instances in the subclasses and then refer to them explicitly:

    object Layer {
      implicit val layerWrites = new Writes[Layer] {
        def writes(x: Layer) = x match {
          case a: CloudLayer         => CloudLayer.cloudLayerWrites.writes(a)
          case b: VerticalVisibility =>
            VerticalVisibility.verticalVisibilityWrites.writes(b)
          case c: SkyClear           => SkyClear.skyClearWrites.writes(c)
        }
      }
    }
    

    You could also just scrap the individual instances and move their contents into the pattern match.

    If you're feeling adventurous, Julien Richard-Foy has a pretty neat enhanced version of the Json.writes, etc. macros that works on sealed type hierarchies.