scray.common.serialization.StringLiteralDesirializer.scala Maven / Gradle / Ivy
package scray.common.serialization
import java.text.SimpleDateFormat
import java.util.UUID
import scala.util._
import org.parboiled2._
import scray.common.exceptions._
import shapeless._
import java.util.Date
/**
* Utility object transforming human readable string literals into corresponding typed data.
*
* Literals can be typed via YAML-like tags or untyped.
*
* Untyped literals transform as follows:
* - alphanumeric strings in simple quotes into string objects
* - numeric strings into integers
* - numeric strings containing a dot into doubles
*
*/
object StringLiteralDeserializer {
/**
* Type tag constants
*/
object TypeTags {
val STR = "!!string"
val INT = "!!int"
val LNG = "!!long"
val DBL = "!!double"
val BOL = "!!bool"
val UID = "!!uuid"
val DAT = "!!date"
}
// date type constants
val DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS"
val TIMEZONE = "GMT"
/**
* Generated literal parser
*/
class LiteralParser(override val input : ParserInput) extends Parser {
def InputLine = rule { literal ~ EOI }
def literal : Rule1[Any] = rule { str | float | long | int | bool }
def str : Rule1[String] = rule { ''' ~ capture(zeroOrMore(CharPredicate.Printable -- '\u0027')) ~ ''' }
def float : Rule1[Double] = rule { capture(oneOrMore(CharPredicate.Digit) ~ '.' ~ oneOrMore(CharPredicate.Digit)) ~> { (in : String) => in.toDouble } }
def int : Rule1[Int] = rule { capture(oneOrMore(CharPredicate.Digit)) ~> { (in : String) => in.toInt } }
def long : Rule1[Long] = rule { capture(oneOrMore(CharPredicate.Digit)) ~ 'L' ~> { (in: String) => in.toLong } }
def bool : Rule1[Boolean] = rule { capture("true" | "false") ~> { (in : String) => in.toBoolean } }
}
/**
* Deserialize untyped literals
*/
def deserialize(literal : String) : Try[_] = {
val parser = new LiteralParser(literal)
parser.InputLine.run() match {
case Success(result) => Success(result)
case Failure(e) => {
if (e.isInstanceOf[ParseError]) sys.error(parser.formatError(e.asInstanceOf[ParseError], showTraces = true))
Failure(new ScrayException(ExceptionIDs.SERIALIZATION_FAULT.getName(), s"Unparsable value literal '$literal'.", e))
}
}
}
/**
* Deserialize typed literals
*/
def deserialize(literal : String, typeTag : String) : Try[_] =
typeTag match {
case tag : String if (tag.equals(TypeTags.STR)) => Success(literal)
case tag : String if (tag.equals(TypeTags.INT)) => cast[Int]("Int", literal, { _.toInt })
case tag : String if (tag.equals(TypeTags.LNG)) => cast[Long]("Long", literal, { _.toLong })
case tag : String if (tag.equals(TypeTags.DBL)) => cast[Double]("Double", literal, { _.toDouble })
case tag : String if (tag.equals(TypeTags.BOL)) => cast[Boolean]("Boolean", literal, { _.toBoolean })
case tag : String if (tag.equals(TypeTags.UID)) => cast[UUID]("UUID", literal, { UUID.fromString(_) })
case tag : String if (tag.equals(TypeTags.DAT)) => cast[Date]("Date", literal, {
val sdf = new SimpleDateFormat(DATEFORMAT)
sdf.setTimeZone(java.util.TimeZone.getTimeZone(TIMEZONE))
sdf.parse(_)
})
case _ => Failure(new ScrayException(ExceptionIDs.SERIALIZATION_FAULT.getName(), s"Illegal typeTag '${tag}'."))
}
/**
* Generic string casting function
*/
def cast[T](typeName : String, literal : String, castfun : (String) => T) : Try[T] = try {
val res = castfun(literal)
Success(res)
} catch {
case e : Exception => Failure(
new ScrayException(
ExceptionIDs.SERIALIZATION_FAULT.getName(), s"Unparsable ${typeName} literal '$literal'.", e))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy