找到要使用的正确类型类

时间:2014-11-16 02:38:52

标签: scala playframework typeclass

我正在尝试在Play应用程序中实现错误处理的类型类解决方案。我想要的是有一些类型类实例代表一些验证(捕获)错误和一个默认类型类实例的任何未经验证(未捕获)错误。

我不知道这是否可行,但到目前为止,这就是我所拥有的:

trait ResponseError[E] {
  def report(e: E)(implicit logger: Logger): Unit
  def materialize(e: E): Result
}

trait ValidatedError[E <: Throwable] extends ResponseError[E] {
  def report(e: E)(implicit logger: Logger): Unit =
    ResponseError.logError(e)
}

trait UnvalidatedError[E <: Throwable] extends ResponseError[E] {
  def report(e: E)(implicit logger: Logger): Unit = {
    ResponseError.logError(e)
    UnvalidatedError.notify(e)
  }
}

object ResponseError {
  def logError(e: Throwable)(implicit logger: Logger): Unit =
    logger.error(e.getMessage)
}

object ValidatedError {
  import java.util.concurrent.{ExecutionException, TimeoutException}

  implicit val executionError = new ValidatedError[ExecutionException] {
    def materialize(e: E): Result =
      play.api.mvc.Results.BadRequest
  }

  implicit val timeoutError   = new ValidatedError[TimeoutException] {
    def materialize(e: E): Result =
      play.api.mvc.Results.RequestTimeout
  }
}

object UnvalidatedError {

  implicit uncaughtError = new UnvalidatedError[Throwable] {
    def materialize(e: E): Result =
      play.api.mvc.Results.ServiceUnavailable
  }

  private def notify(e: Throwable) = ??? // send email notification
}

但是,在回到我的ValidatedError类型类实例之前,如何确保首先尝试我的UnvalidatedError类型类实例?

1 个答案:

答案 0 :(得分:1)

你去吧。有关详细信息,请参阅我的评论。

  import java.util.concurrent.{TimeoutException, ExecutionException}

  type Result = String

  val badRequest: Result = "BadRequest"
  val requestTimeout: Result = "RequestTimeout"
  val serviceUnavailable: Result = "ServiceUnavailable"

  class Logger {
    def error(s: String) = println(s + "\n")
  }

  trait ResponseError[E] {
    def report(e: E)(implicit logger: Logger): Unit
    def materialize(e: E): Result
  }

  trait ValidatedError[E <: Throwable] extends UnvalidatedError[E] {
    override def report(e: E)(implicit logger: Logger): Unit =
      ResponseError.logError(e, validated = true)
  }

  trait UnvalidatedError[E <: Throwable] extends ResponseError[E] {
    def report(e: E)(implicit logger: Logger): Unit = {
      ResponseError.logError(e, validated = false)
      UnvalidatedError.notify(e)
    }
  }

  object ResponseError {
    def logError(e: Throwable, validated: Boolean)(implicit logger: Logger): Unit =
      logger.error({
        validated match {
          case true => "VALIDATED : "
          case false => "UNVALIDATED : "
        }
      } + e.getMessage)
  }

  object ValidatedError {
    import java.util.concurrent.{ExecutionException, TimeoutException}

    implicit def executionError[E <: ExecutionException] = new ValidatedError[E] {
      def materialize(e: E): Result =
        badRequest
    }

    implicit def timeoutError[E <: TimeoutException]  = new ValidatedError[E] {
      def materialize(e: E): Result =
        requestTimeout
    }
  }

  object UnvalidatedError {

    implicit def uncaughtError[E <: Throwable] = new UnvalidatedError[E] {
      def materialize(e: E): Result =
        serviceUnavailable
    }

    private def notify(e: Throwable) = println("Sending email: " + e) // send email notification
  }

  def testTypeclass[E](e: E)(implicit logger: Logger, ev: ResponseError[E]): Unit ={
    ev.report(e)

  }

  import ValidatedError._
  import UnvalidatedError._

  implicit val logger: Logger = new Logger

  val executionErr = new ExecutionException(new Throwable("execution exception!"))

  testTypeclass(executionErr)

  val timeoutErr = new TimeoutException("timeout exception!")

  testTypeclass(timeoutErr)

  val otherErr = new Exception("other exception!")

  testTypeclass(otherErr)

输出:

  VALIDATED : java.lang.Throwable: execution exception!

  VALIDATED : timeout exception!

  UNVALIDATED : other exception!

  Sending email: java.lang.Exception: other exception!