0

I am using Extraction.decompose to produce a JValue and it is intermittently failing. I am asking it to decompose a Seq of the following case class:

case class Item(locators: Seq[String], dateAdded: DateTime = new DateTime(0L), newVersionSinceCuration: Option[Boolean] = None)

The DateTime is a org.joda.time.DateTime.

The same line of code will work the majority of times but every few minutes will fail with the following stack trace:

java.lang.ArrayIndexOutOfBoundsException: 14
    at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:453)
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2397)
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2312)
    at java.util.Calendar.complete(Calendar.java:2268)
    at java.util.Calendar.get(Calendar.java:1826)
    at java.text.SimpleDateFormat.subFormat(SimpleDateFormat.java:1119)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:966)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:936)
    at java.text.DateFormat.format(DateFormat.java:345)
    at org.json4s.DefaultFormats$$anon$4.format(Formats.scala:358)
    at org.json4s.ext.DateTimeSerializer$$anonfun$$lessinit$greater$4$$anonfun$apply$8.applyOrElse(JodaTimeSerializers.scala:78)
    at scala.PartialFunction$OrElse.apply(PartialFunction.scala:167)
    at org.json4s.ext.InstantSerializer$$anonfun$$lessinit$greater$3$$anonfun$apply$6.applyOrElse(JodaTimeSerializers.scala:57)
    at scala.PartialFunction$OrElse.apply(PartialFunction.scala:167)
    at org.json4s.ext.DurationSerializer$$anonfun$$lessinit$greater$2$$anonfun$apply$4.applyOrElse(JodaTimeSerializers.scala:47)
    at scala.PartialFunction$OrElse.apply(PartialFunction.scala:167)
    at scala.PartialFunction$class.applyOrElse(PartialFunction.scala:123)
    at scala.collection.AbstractMap.applyOrElse(Map.scala:59)
    at scala.PartialFunction$OrElse.apply(PartialFunction.scala:167)
    at org.json4s.Extraction$.internalDecomposeWithBuilder(Extraction.scala:146)
    at org.json4s.Extraction$.addField$1(Extraction.scala:110)
    at org.json4s.Extraction$.decomposeObject$1(Extraction.scala:140)
    at org.json4s.Extraction$.internalDecomposeWithBuilder(Extraction.scala:228)
    at org.json4s.Extraction$.internalDecomposeWithBuilder(Extraction.scala:189)
    at org.json4s.Extraction$.decomposeWithBuilder(Extraction.scala:64)
    at org.json4s.Extraction$.decompose(Extraction.scala:242)

    ...

So it seems to fail to parse the DateTime. I'm overriding the date format as per the Json4s documentation with the following:

implicit def json4sFormats = new DefaultFormats {
    override val dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX")
    dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"))
} ++ JodaTimeSerializers.all

I've googled around ArrayIndexOutOfBoundsException problems with sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate and SimpleDateFormat and there's lots of posts about SimpleDateFormat not being thread safe. That seems like it could explain the error but I can see that Json4s wraps the dateFormatter in a ThreadLocal, which I understand should make it thread safe.

Any thoughts on what might be going on here?

I am using Scala 2.11.8, Json4s 3.5.1, OpenJDK 1.8.0.

Cheers, Paul

Paul L.
  • 3
  • 1

1 Answers1

1

You are defeating the ThreadLocal by making your dateFormatter a val instead of def as in the linked source for DefaultFormats, so all threads end up referring to the same instance. Of course, when you make it a def, setTimeZone needs to be done inside the definition.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487