All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finatra.jackson.serde.JodaDatetimeDeserializer.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finatra.jackson.serde

import com.fasterxml.jackson.core.{JsonParser, JsonToken}
import com.fasterxml.jackson.databind.{DeserializationContext, JsonMappingException}
import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat
import com.fasterxml.jackson.datatype.joda.deser.JodaDateDeserializerBase
import com.twitter.util.{Return, Try}
import org.joda.time.{DateTime, DateTimeZone}

/**
 * A Datetime deserializer with improved exception handling (compared to jackson-datatype-joda)
 */
@deprecated(
  "Users should prefer JDK8 equivalent classes and associated Jackson support",
  "2021-04-12")
private[finatra] class JodaDatetimeDeserializer(format: JacksonJodaDateFormat)
    extends JodaDateDeserializerBase[DateTime](classOf[DateTime], format) {

  override def withFormat(jacksonJodaDateFormat: JacksonJodaDateFormat): JodaDatetimeDeserializer =
    new JodaDatetimeDeserializer(format)

  def deserialize(jp: JsonParser, ctxt: DeserializationContext): DateTime = {
    try {
      jp.getCurrentToken match {
        case JsonToken.NOT_AVAILABLE | JsonToken.START_OBJECT =>
          handleToken(jp.nextToken, jp, ctxt)
        case _ =>
          handleToken(jp.currentToken, jp, ctxt)
      }
    } catch {
      case e: IllegalArgumentException =>
        throw JsonMappingException.from(
          ctxt,
          "error parsing '" + jp.getText + "' into an ISO 8601 datetime",
          e)
    }
  }

  private def handleToken(
    token: JsonToken,
    jp: JsonParser,
    ctxt: DeserializationContext
  ): DateTime = token match {
    case JsonToken.VALUE_NUMBER_INT =>
      val value: Long = jp.getLongValue
      parseFromLong(ctxt, value)
    case JsonToken.VALUE_STRING =>
      val value: String = jp.getText.trim
      if (value.isEmpty) {
        throw JsonMappingException.from(ctxt, "field cannot be empty")
      } else {
        // First, attempt to convert as a String value (for backwards-compatibility),
        // Long millis will fail and we then attempt to parse with value.toLong
        Try(this._format.createParser(ctxt).parseDateTime(value)) match {
          case Return(result) => result
          case _ => parseFromLong(ctxt, value.toLong)
        }
      }
    case _ =>
      this._handleNotNumberOrString(jp, ctxt)
  }

  private def parseFromLong(ctxt: DeserializationContext, value: Long): DateTime = {
    if (value < 0) {
      throw JsonMappingException.from(ctxt, "field cannot be negative")
    } else {
      val tz = if (this._format.isTimezoneExplicit) {
        this._format.getTimeZone
      } else {
        DateTimeZone.forTimeZone(ctxt.getTimeZone)
      }
      new DateTime(value, tz)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy