4

I'm having an issue with org.json4s (scala), joda.time.LocalDate and org.json4s.ext.JodaTimeSerializers. Given that JodaTimeSerializers.all has a LocalDate conversion in it, i was hoping that i could do the following, but I get the exception shown after

scala> import org.json4s.JString
import org.json4s.JString

scala> import org.joda.time.LocalDate
import org.joda.time.LocalDate

scala> import org.json4s.ext.JodaTimeSerializers
import org.json4s.ext.JodaTimeSerializers

scala> import org.json4s._
import org.json4s._

scala> implicit val formats: Formats = DefaultFormats ++ JodaTimeSerializers.all
formats: org.json4s.Formats = org.json4s.Formats$$anon$3@693d3d7f

scala> val jDate = JString("2016-01-26")
jDate: org.json4s.JsonAST.JString = JString(2016-01-26)

scala> jDate.extract[LocalDate]
org.json4s.package$MappingException: Can't convert JString(2016-01-26) to class org.joda.time.LocalDate

Other the other hand, this works (not surprisingly)

scala> val jodaDate = LocalDate.parse(jDate.values)

I've tried to create a custom Serializer, which never gets called b/c it falls into the JodaSerializer realm it seems. I have also created a custom Deserializer that will work with Java.time.LocalDate (int and bytes from strings), but java.time.LocalDate messes with some other code which is likely a different question...this one is: I'm looking for clues by JodaTimeSerializers.all can not parse JString(2016-01-26), or any date string.

The top of the exception is: org.json4s.package$MappingException:

Can't convert JString(2016-01-01) to class org.joda.time.LocalDate (JodaTimeSerializers.scala:126)

Edit This is still biting me, so dug a bit further and its reproducible with the following.

import org.joda.time.LocalDate
import org.json4s.ext.JodaTimeSerializers
import org.json4s._
implicit val formats: Formats = DefaultFormats ++ JodaTimeSerializers.all
import org.joda.time.LocalDate
case class MyDate(myDate: LocalDate)
val stringyDate =
"""
{
  "myDate" : "2016-01-01"
}
"""
import org.json4s.jackson.JsonMethods.parse
parse(stringyDate).extract[MyDate]

org.json4s.package$MappingException: No usable value for myDate
Can't convert JString(2016-01-01) to class org.joda.time.LocalDate

This seems to happen b/c on line 125 of JodaTimeSerializers.scala, its not a JObject, it is a JString, so it falls into the value case on line 126, which throws the error.

Adding this here in case it bites someone else and hopefully get some assistance fixing it...but now i'm late. I have moved the code locally hopefully to come up with a fix tomorrow.

ekydfejj
  • 339
  • 2
  • 14
  • i've hacked my way around this on the scalatra side, but now play can not deserialize it b/c its comes through as a sub-object of {year: 2016, month: 03: day 09} rather than just a simple date. – ekydfejj Mar 09 '16 at 22:41
  • You need both sides to agree on a common format. So either teach play how to read the date object, or teach the other side play's date format by writing a custom `Serializer[LocalDate]` instead of using the `JodaTimeSerializer.all`. – Stefan Ollinger Mar 10 '16 at 00:54
  • BEWARE: Json4s is [vulnerable under DoS/DoW attacks](https://github.com/json4s/json4s/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+denial)! – Andriy Plokhotnyuk Jun 02 '20 at 08:13

2 Answers2

2

This works. I define a custom serializer for LocalDate.

import org.json4s.JString
import org.joda.time.LocalDate
import org.json4s._

case object LocalDateSerializer
    extends CustomSerializer[LocalDate](
      format =>
        ({
          case JString(s) => LocalDate.parse(s)
        }, Map() /* TO BE IMPLEMENTED */)
    )

implicit val formats: Formats = DefaultFormats + LocalDateSerializer
val jDate = JString("2016-01-26")
jDate.extract[LocalDate] // res173: org.joda.time.LocalDate = 2016-01-26
yiksanchan
  • 1,890
  • 1
  • 13
  • 37
1

The new serializers are included in the library, but not in the default formats:

implicit val formats: Formats = DefaultFormats ++ JavaTimeSerializers.all
  • 1
    Unfortunately though the `LocalDate` serializer in `JavaTimeSerializers` does NOT cope with a single date string. It serializes and expects an object with fields `day`, `month` and `year`. Which isn't terribly helpful. – Steve Sowerby Jun 27 '20 at 12:27