From e45e981634c1bdccd02bae4e37fac1c1e654cdfe Mon Sep 17 00:00:00 2001 From: vlad Date: Mon, 25 Jul 2016 15:00:39 -0400 Subject: Some more JSON formatters and json,rest packages rearranged --- src/main/scala/com/drivergrp/core/json.scala | 87 ++++++++++++++++++++++++++++ src/main/scala/com/drivergrp/core/rest.scala | 54 +---------------- 2 files changed, 88 insertions(+), 53 deletions(-) create mode 100644 src/main/scala/com/drivergrp/core/json.scala (limited to 'src/main/scala/com/drivergrp') diff --git a/src/main/scala/com/drivergrp/core/json.scala b/src/main/scala/com/drivergrp/core/json.scala new file mode 100644 index 0000000..6828a07 --- /dev/null +++ b/src/main/scala/com/drivergrp/core/json.scala @@ -0,0 +1,87 @@ +package com.drivergrp.core + +import akka.http.scaladsl.model.Uri.Path +import akka.http.scaladsl.server.PathMatcher.Matched +import akka.http.scaladsl.server.{PathMatcher, _} +import com.drivergrp.core.time.Time +import spray.json.{DeserializationException, JsNumber, _} + +import scala.reflect.runtime.universe._ + +object json { + + def IdInPath[T]: PathMatcher1[Id[T]] = + PathMatcher("""[+-]?\d*""".r) flatMap { string => + try Some(Id[T](string.toLong)) + catch { case _: IllegalArgumentException => None } + } + + implicit def idFormat[T] = new RootJsonFormat[Id[T]] { + def write(id: Id[T]) = JsNumber(id) + + def read(value: JsValue) = value match { + case JsNumber(id) => Id[T](id.toLong) + case _ => throw new DeserializationException("Id expects number") + } + } + + def NameInPath[T]: PathMatcher1[Name[T]] = new PathMatcher1[Name[T]] { + def apply(path: Path) = Matched(Path.Empty, Tuple1(Name[T](path.toString))) + } + + implicit def nameFormat[T] = new RootJsonFormat[Name[T]] { + def write(name: Name[T]) = JsString(name) + + def read(value: JsValue): Name[T] = value match { + case JsString(name) => Name[T](name) + case _ => throw new DeserializationException("Name expects string") + } + } + + def TimeInPath: PathMatcher1[Time] = + PathMatcher("""[+-]?\d*""".r) flatMap { string => + try Some(Time(string.toLong)) + catch { case _: IllegalArgumentException => None } + } + + implicit val timeFormat = new RootJsonFormat[Time] { + def write(time: Time) = JsObject("timestamp" -> JsNumber(time.millis)) + + def read(value: JsValue): Time = value match { + case JsObject(fields) => + fields + .get("timestamp") + .flatMap { + case JsNumber(millis) => Some(Time(millis.toLong)) + case _ => None + } + .getOrElse(throw new DeserializationException("Time expects number")) + case _ => throw new DeserializationException("Time expects number") + } + } + + class EnumJsonFormat[T](mapping: (String, T)*) extends JsonFormat[T] { + private val map = mapping.toMap + + override def write(value: T): JsValue = { + map.find(_._2 == value).map(_._1) match { + case Some(name) => JsString(name) + case _ => serializationError(s"Value $value is not found in the mapping $map") + } + } + + override def read(json: JsValue): T = json match { + case JsString(name) => + map.getOrElse(name, throw new DeserializationException(s"Value $name is not found in the mapping $map")) + case _ => deserializationError("Expected string as enumeration value, but got " + json) + } + } + + class ValueClassFormat[T: TypeTag](writeValue: T => BigDecimal, create: BigDecimal => T) extends JsonFormat[T] { + def write(valueClass: T) = JsNumber(writeValue(valueClass)) + def read(json: JsValue): T = json match { + case JsNumber(value) => create(value) + case _ => deserializationError(s"Expected number as ${typeOf[T].getClass.getName}, but got " + json) + } + } +} diff --git a/src/main/scala/com/drivergrp/core/rest.scala b/src/main/scala/com/drivergrp/core/rest.scala index 914e1ec..3f3a68e 100644 --- a/src/main/scala/com/drivergrp/core/rest.scala +++ b/src/main/scala/com/drivergrp/core/rest.scala @@ -2,21 +2,18 @@ package com.drivergrp.core import akka.actor.ActorSystem import akka.http.scaladsl.Http -import akka.http.scaladsl.model.Uri.Path import akka.http.scaladsl.model.{HttpRequest, HttpResponse} -import akka.http.scaladsl.server.PathMatcher.Matched import akka.http.scaladsl.server.{Directive, _} import akka.http.scaladsl.util.FastFuture._ import akka.stream.ActorMaterializer import akka.util.Timeout import com.drivergrp.core.logging.Logger import com.drivergrp.core.stats.Stats -import com.drivergrp.core.time.{Time, TimeRange} +import com.drivergrp.core.time.TimeRange import com.drivergrp.core.time.provider.TimeProvider import com.github.swagger.akka.model._ import com.github.swagger.akka.{HasActorSystem, SwaggerHttpService} import com.typesafe.config.Config -import spray.json.{DeserializationException, JsNumber, JsObject, JsString, JsValue, RootJsonFormat} import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} @@ -24,7 +21,6 @@ import scala.language.postfixOps import scala.util.{Failure, Success, Try} import scalaz.{Failure => _, Success => _, _} - object rest { trait RestService { @@ -68,54 +64,6 @@ object rest { } } - object basicFormats { - - def IdInPath[T]: PathMatcher1[Id[T]] = - PathMatcher("""[+-]?\d*""".r) flatMap { string ⇒ - try Some(Id[T](string.toLong)) catch { case _: IllegalArgumentException ⇒ None } - } - - implicit def idFormat[T] = new RootJsonFormat[Id[T]] { - def write(id: Id[T]) = JsNumber(id) - - def read(value: JsValue) = value match { - case JsNumber(id) => Id[T](id.toLong) - case _ => throw new DeserializationException("Id expects number") - } - } - - def NameInPath[T]: PathMatcher1[Name[T]] = new PathMatcher1[Name[T]] { - def apply(path: Path) = Matched(Path.Empty, Tuple1(Name[T](path.toString))) - } - - implicit def nameFormat[T] = new RootJsonFormat[Name[T]] { - def write(name: Name[T]) = JsString(name) - - def read(value: JsValue): Name[T] = value match { - case JsString(name) => Name[T](name) - case _ => throw new DeserializationException("Name expects string") - } - } - - def TimeInPath: PathMatcher1[Time] = - PathMatcher("""[+-]?\d*""".r) flatMap { string ⇒ - try Some(Time(string.toLong)) catch { case _: IllegalArgumentException ⇒ None } - } - - implicit val timeFormat = new RootJsonFormat[Time] { - def write(time: Time) = JsObject("timestamp" -> JsNumber(time.millis)) - - def read(value: JsValue): Time = value match { - case JsObject(fields) => - fields.get("timestamp").flatMap { - case JsNumber(millis) => Some(Time(millis.toLong)) - case _ => None - }.getOrElse(throw new DeserializationException("Time expects number")) - case _ => throw new DeserializationException("Time expects number") - } - } - } - trait OptionTDirectives { /** -- cgit v1.2.3