Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jsonx formatCaseClass for joda time DateTime field #59

Open
lucky0604 opened this issue Sep 22, 2018 · 2 comments
Open

Jsonx formatCaseClass for joda time DateTime field #59

lucky0604 opened this issue Sep 22, 2018 · 2 comments

Comments

@lucky0604
Copy link

When I use jsonx and joda time in a case class.

import ai.x.play.json.Jsonx
import org.joda.time.DateTime
// case class
case class A (var a: Option[DateTime] = None)
// json object
object A { implicit val a = Jsonx.formatCaseClass[A]}

I also use slickless and shapeless to resolve the 22 params.
It throws the error:

could not find implicit value for parameter helper: play.api.libs.json.Reads[Option[org.joda.time.DateTime]]
TRIGGERED BY: could not find implicit value for parameter helper: ai.x.play.json.OptionValidationDispatcher[Option[org.joda.time.DateTime]]
TO SOLVE THIS
1. Make sure there is a Reads[Option[org.joda.time.DateTime]] or Format[Option[org.joda.time.DateTime]] in the implicit scope
2. In case of Reads[Option[...]] you need to either
   import ai.x.play.json.implicits.optionWithNull // suggested
   or
   import ai.x.play.json.implicits.optionNoError // buggy play-json 2.3 behavior
3. In case of Reads[... .type]
   import ai.x.play.json.SingletonEncoder.simpleName
   import ai.x.play.json.implicits.formatSingleton
@franklinchou
Copy link

franklinchou commented Oct 2, 2018

I'm not sure if there should be forward looking support for joda time, since Java 8's java.time library is widely considered to be superior and that any new applications developed on Java should be using java.time. See here.

@ThatGuyMichael
Copy link

To get joda time to work with Jsonx, you'll need to include an implicit joda format. Below is a full implementation for both Format[DateTime] and Format[Option[DateTime]]:

def jsonWrites(format: String): Writes[DateTime] = { dt =>
    JsString(dt.toString(format))
}

def jsonOptionalWrites(format: String): Writes[Option[DateTime]] = { dtOpt =>
    dtOpt.map(dt => JsString(dt.toString(format))).getOrElse(JsNull)
}

val dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

def jsonReads(): Reads[DateTime] = {
    case JsNumber(d) => JsSuccess(new DateTime(d.toLong))
    case JsString(s) =>
        scala.util.control.Exception.nonFatalCatch[DateTime].opt(DateTime.parse(s, DateTimeFormat.forPattern(dateFormat))) match {
            case Some(d) => JsSuccess(d)
            case _ => JsError(Seq(JsPath() -> Seq(
                JsonValidationError("error.expected.jodadate.format")
            )))
        }
    case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("error.expected.date"))))
}

def jsonOptionalReads(): Reads[Option[DateTime]] = {
    case JsNumber(d) => JsSuccess(Some(new DateTime(d.toLong)))
    case JsString(s) =>
        scala.util.control.Exception.nonFatalCatch[DateTime].opt(DateTime.parse(s, DateTimeFormat.forPattern(dateFormat))) match {
            case Some(d) => JsSuccess(Some(d))
            case _ => JsError(Seq(JsPath() -> Seq(
                JsonValidationError("error.expected.jodadate.format")
            )))
        }
    case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("error.expected.date"))))
}

implicit val dateTimeFormat: Format[DateTime] = new Format[DateTime] {
    override def writes(o: DateTime): JsValue = jsonWrites("yyyy-MM-dd HH-mm-ss").writes(o)
    override def reads(json: JsValue): JsResult[DateTime] = jsonReads().reads(json)
}

implicit val dateTimeFormatOption: Format[Option[DateTime]] = new Format[Option[DateTime]] {
    override def writes(o: Option[DateTime]): JsValue = jsonOptionalWrites("yyyy-MM-dd HH-mm-ss").writes(o)
    override def reads(json: JsValue): JsResult[Option[DateTime]] = jsonOptionalReads().reads(json)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants