Search code examples
scalaplayframeworkplay-json

Play Json Validation is failing on Date field with Error: [error.expected.date.isoformat]


I have a JsonValidationError.

This is my model:

case class Account(id: Long, name: String, birthDate: LocalDate)
object Account {
  implicit val accountFormat = Json.format[Account]
}

And this is part of my controller action:

def updateProfile = Action.async(parse.json) { implicit request =>
  val res = request.body.validate[Account]
  logger.info(request.body.toString)
  logger.info(res.toString)

  ...
}

I have this output:

[info] c.a.AccountController - {"id":1,"name":"John","birthDate":"1983-02-11T23:00:00.000Z"}
[info] c.a.AccountController - JsError(List((/birthDate,List(JsonValidationError(List(error.expected.date.isoformat),ArraySeq(ParseCaseSensitive(false)(Value(Year,4,10,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2))[Offset(+HH:MM:ss,'Z')])))))

The data coming from the client seems to be valid, I don't understand that Error, I think the birthDate is in the isoFormat, so what can be the issue here ?

Please help.


Solution

  • The input has a different format than expected for java.time.LocalDate.

    Try the following custom codec to make the issue gone:

    case class Account(id: Long, name: String, birthDate: LocalDate)
    object Account {
      implicit val accountFormat: OFormat[Account] = {
        implicit val customLocalDateFormat: Format[LocalDate] = Format(
          Reads(js => JsSuccess(Instant.parse(js.as[String]).atZone(ZoneOffset.UTC).toLocalDate)),
          Writes(d => JsString(d.atTime(LocalTime.of(23, 0)).atZone(ZoneOffset.UTC).toInstant.toString)))
        Json.format[Account]
      }
    }
    
    val json = """{"id":1,"name":"John","birthDate":"1983-02-11T23:00:00.000Z"}"""
    val account = Json.parse(json).as[Account]
    println(account)
    println(Json.toJson(account))
    

    An expected output of this code snippet is:

    Account(1,John,1983-02-11)
    {"id":1,"name":"John","birthDate":"1983-02-11T23:00:00Z"}