Play JSON Error When Parsing from JSON into Case class

62 views Asked by At

I have a simple case class as below:

case class SmartMeterData(
     dateInterval: SmartMeterDataInterval = HalfHourInterval(),
     powerUnit: PowerUnit = PowerUnit.KWH,
     smartMeterId: String,
     timestamp: String,
     value: Double
)

This case class is contained in the package called models and in the models package I also have a package object where I define all the implicit json mappings. For this case, I have the following implicits:

implicit val currencyReads: Reads[Currency] = new Reads[Currency] {
    def reads(json: JsValue): JsResult[Currency] =
      json match {
        case JsString(currency) => JsSuccess(Currency.getInstance(currency))
        case err => JsError(s"Invalid Currency format ${err.toString()}")
      }
  }

  implicit val currencyWrites: Writes[Currency] = new Writes[Currency] {
    def writes(currency: Currency): JsString = JsString(currency.toString)
  }

  // The default DateTime format that we use for all DateTime
  // values that this application produces
  val dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  implicit val jodaDateReads: Reads[Imports.DateTime] = Reads[DateTime](js =>
    js.validate[String].map[DateTime](dtString =>
      DateTime.parse(dtString, DateTimeFormat.forPattern(dateFormat))
    )
  )

  implicit val jodaDateWrites: Writes[DateTime] = new Writes[DateTime] {
    def writes(d: DateTime): JsValue = JsString(d.toString())
  }
  
  implicit lazy val usagePriceFormat: OFormat[UsagePrice] = Json.format[UsagePrice]
  implicit lazy val providerFormat: OFormat[Provider] = Json.format[Provider]
  implicit lazy val electricityPriceFormat: OFormat[ElectricityPrice] = Json.format[ElectricityPrice]

  implicit lazy val hhIntervalFormat = Json.format[HalfHourInterval]
  implicit lazy val fhIntervalFormat = Json.format[FullHourInterval]
  implicit lazy val intervalFormat = Json.format[SmartMeterDataInterval]

  implicit val powerUnitReads: Reads[PowerUnit] = new Reads[PowerUnit] {
    def reads(json: JsValue): JsResult[PowerUnit] =
      json match {
        case JsString("KWH") => JsSuccess(PowerUnit.KWH)
        case JsString("WH") => JsSuccess(PowerUnit.WH)
        case JsString("MWH") => JsSuccess(PowerUnit.MWH)
        case err => JsError(s"Invalid PowerUnit format ${err.toString()}")
      }
  }

  implicit val powerUnitWrites: Writes[PowerUnit] = new Writes[PowerUnit] {
    def writes(powerUnit: PowerUnit): JsValue = powerUnit match {
      case WH => Json.toJson("WH")
      case KWH => Json.toJson("KWH")
      case MWH => Json.toJson("MWH")
    }
  }

I then started to write some simple tests to parse the JSON's and I'm getting this error:

method fromJson: (implicit fjs: play.api.libs.json.Reads[T]): play.api.libs.json.JsResult[T] does not take type parameters.
    Json.fromJson(json)[SmartMeterData].asEither match {

Here is what I'm trying to do:

"SmartMeterData" should "parse from a JSON AST" in {
    val json: JsValue = Json.parse("""
      {
        "dateInterval" : "HH",
        "powerUnit" : "KWH",
        "smartMeterId" : "LCID-001-X-54",
        "timestamp" : "2012-10-12 00:30:00.0000000",
        "value" : 23.0
      }
      """)
    Json.fromJson(json)[SmartMeterData].asEither match {
      case Left(_) => fail("verdammt")
      case Right(smartMeterData) => {
        assert(smartMeterData.timeStamp equals "2012-10-12 00:30:00.0000000")
      }
    }
}
1

There are 1 answers

0
Tomer Shetah On BEST ANSWER

You should first provide the type, and then the argument. The call should be:

Json.fromJson[SmartMeterData](json)

and NOT:

Json.fromJson(json)[SmartMeterData]