Scala, convert joda.LocalDateTime to json with play 2.5

451 Views Asked by At

I'm new to Scala and my question is about Json serialization using play (2.5) for Joda's optional value My Inputs: 1.

import org.joda.time.LocalDateTime
     case class User(
                     name: String, 
                     lastLogin: Option[LocalDateTime])
    object User {
      implicit val serializers = JsonSerializers
      implicit val UserFormat: Format[User] = Format(serializers.UserReads, serializers.UserWrites)
    }
  1. Serializers

    import com.dtos.{User}
    import org.joda.time.LocalDateTime
    import org.joda.time.format.DateTimeFormat
    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    object JsonSerializers {
      val dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
    
      implicit val UserReads: Reads[User] = (
        (JsPath \ "name").read [String] and
          (JsPath \ "active").read [Boolean] and
          (JsPath \\ "$ldt").read[LocalDateTime]
        )(User.apply _)
    
      implicit val UserWrites: Writes[User] = (
        (JsPath \ "name").write [String] and
          (JsPath \ "active").write [Boolean] and
          (JsPath \ "lastLogin" \ "$ldt") .write [LocalDateTime]
        )(unlift (User.unapply))
    }
    
  2. Test Object:

    object MainTest extends App {    
      val value: JsValue = Json.parse("{ \"name\" : \"hello\" , \"lastLogin\" : {\"$ldt\":\"2018-09-09T11:06:27.655\"} }")
      println("First Output:")
      println(Json.toJson(new MyUser("user", LocalDateTime.now)))
      println("Second Output:")
      println(Json.fromJson(value))    
    }
    

Questions: 1. How to manage Option value during UserReads/UserWrites? I'm getting the following Error:

overloaded method value apply with alternatives: [B](f: B => (String, Boolean, org.joda.time.LocalDateTime))(implicit fu: play.api.libs.functional.ContravariantFunctor[play.api.libs.json.Reads])play.api.libs.json.Reads[B] [B](f: (String, Boolean, org.joda.time.LocalDateTime) => B)(implicit fu: play.api.libs.functional.Functor[play.api.libs.json.Reads])play.api.libs.json.Reads[B] cannot be applied to ((String, Boolean, Option[org.joda.time.LocalDateTime]) => com.dtos.User) (JsPath \ "active").read [Boolean] and

  1. can't make it work for the input Json Structure of User, when $ldt is a sub element of lastLogin:

     val value: JsValue = Json.parse("{ \"name\" : \"hello\" , \"lastLogin\" : {\"$ldt\":\"2018-09-09T11:06:27.655\"} }")
    
    (means User is defined by:
    "name\":\"myName\",
    \"active\":true,
    \"lastLogin\":{\"$ldt\":\"2018-09-09T11:06:27.655\"}
    }
    )
    
1

There are 1 best solutions below

0
On

I think what you are missing is the serializer Format[LocalDateTime].

Option is supported out of the box.

Taken from another Stackoverflow answer:

import org.joda.time.LocalDateTime
import org.joda.time.format.ISODateTimeFormat

implicit val readsJodaLocalDateTime = Reads[LocalDateTime](js =>
  js.validate[String].map[LocalDateTime](dtString =>
    LocalDateTime.parse(dtString, ISODateTimeFormat.basicDateTime())
  )
)

See here the whole answer: custom-jodatime-serializer-using-play-frameworks-json-library

By the way for case classes you can add a serializer like this:

object User {
  implicit val jsonFormat: Format[User] = Json.format[User]
}