Several times in my application, I handle the errors of a future the same way.
For instance I do:
future map(r => println(r)) recover {
case arithmeticException => log("arithmetic exception")
case NonFatal(e) => log(e)
}
How can I extract a method from the recover part in order to reuse it elsewhere?
For instance, I would like to do something like:
def handleException(): PartialFunction[Throwable, Unit] = {
case arithmeticException => log("arithmetic exception")
case NonFatal(e) => log(e)
}
and use it like this:
future map(r => println(r)) recover { handleException() }
How can I do this?
val handleException: PartialFunction[Throwable, Unit] = {
case arithmeticException => log("arithmetic exception")
case NonFatal(e) => log(e)
}
future.map(println).recover(handleException)
Related
def update() = AuthAction.async(parse.json) { implicit request =>
val list = request.body.asInstanceOf[JsArray].value
list.foreach( mapping => {
repository.update()
}.andThen {
case Success(value) => repository.update2()
case Failure(exception) => {
BadRequest(errorResponse(Json.toJson(""), "updation failed"))
}
})
}
I have a controller function where I want to wait for a DB repo function ( repository.update2() )to complete and then send a response, but its saying "Found Unit expected Future[Result]"
Your success claus is presumably returning Unit where a Future response is required. Try this:
.andThen {
case Success(value) =>
repository.update2()
Future.successful(Ok("repository updated"))
case Failure(exception) =>
Future.successful(BadRequest(exception.getMessage())))
}
I would like to update the Failure exception of a Try to provide a more understandable failure.
I successfully do this by using the following implementation:
case class NoDataAvailableException() extends Exception
[...]
Try(...) match {
case Success(f) => Success(f)
case Failure(_) => Failure(NoDataAvailableException())
}
But I think this implementation is not really elegant, so my question is:
Is there a way to do this more elegantly ?
You could use recoverWith with accepts a PartialFunction[Throwable, Try[U]]. This would allow you to map specific exceptions to successes or failures, as you wish.
case class MyException() extends Exception
Try(1 / 0) recoverWith {
case _: ArithmeticException => Failure(new MyException())
// other exceptions ...
}
You could also use an implicit class to add method of your own to Try that lets you specifically map exceptions.
implicit class TryExtension[A](t: Try[A]) {
def mapFailure(pf: PartialFunction[Throwable, Throwable]): Try[A] =
t.recoverWith(pf.andThen(Failure.apply))
}
scala> Try(1 / 0).mapFailure { case _ => new MyException }
res3: scala.util.Try[Int] = Failure(MyException)
You are looking for Try.recoverWith
Try(...) recoverWith {
case _ => Failure(NoDataAvailableException())
}
How about using try.recover or try.recoverWith?
I have the following code that silently fail without catching any error:
(actor ? GetRowCount()).mapTo[Either[Rejection, Long]] map {
case Left(x) => ctx.reject(x)
case Right(totalRows) => ctx.complete(totalRows)
}
When GetRowCount() does not return a Long, but a String for instance, no error was caught and it just silently fail.
I am thinking to use the following:
(actor ? GetRowCount()).mapTo[Either[Rejection, Any]] map {
case Left(x) => ctx.reject(x)
case Right(totalRows: Long) => ctx.complete(totalRows)
case _ => ctx.reject(Rejection("Type mismatch"))
}
But is there a better answer?
I would use recover or recoverWith
(actor ? GetRowCount).mapTo[Either[Rejection, Long]] map {
case Left(x) => ctx.reject(x)
case Right(totalRows) => ctx.complete(totalRows)
} recover {
case e: Throwable =>
logger.error(e, "Some thing wrong while performing ask")
//throw an error or return something here
}
I have a Future[T] and I want to map the result, on both success and failure.
Eg, something like
val future = ... // Future[T]
val mapped = future.mapAll {
case Success(a) => "OK"
case Failure(e) => "KO"
}
If I use map or flatmap, it will only map successes futures. If I use recover, it will only map failed futures. onComplete executes a callback but does not return a modified future. Transform will work, but takes 2 functions rather than a partial function, so is a bit uglier.
I know I could make a new Promise, and complete that with onComplete or onSuccess/onFailure, but I was hoping there was something I was missing that would allow me to do the above with a single PF.
Edit 2017-09-18: As of Scala 2.12, there is a transform method that takes a Try[T] => Try[S]. So you can write
val future = ... // Future[T]
val mapped = future.transform {
case Success(_) => Success("OK")
case Failure(_) => Success("KO")
}
For 2.11.x, the below still applies:
AFAIK, you can't do this directly with a single PF. And transform transforms Throwable => Throwable, so that won't help you either. The closest you can get out of the box:
val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO"}
That said, implementing your mapAll is trivial:
implicit class RichFuture[T](f: Future[T]) {
def mapAll[U](pf: PartialFunction[Try[T], U]): Future[U] = {
val p = Promise[U]()
f.onComplete(r => p.complete(Try(pf(r))))
p.future
}
}
Since Scala 2.12 you can use transform to map both cases:
future.transform {
case Success(_) => Try("OK")
case Failure(_) => Try("KO")
}
You also have transformWith if you prefer to use a Future instead of a Try. Check the documentation for details.
In a first step, you could do something like:
import scala.util.{Try,Success,Failure}
val g = future.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map {
case Success(s) => ...
case Failure(t) => ...
}
where T is the type of the future result. Then you can use an implicit conversion to add this structure the Future trait as a new method:
implicit class MyRichFuture[T]( fut: Future[T] ) {
def mapAll[U]( f: PartialFunction[Try[T],U] )( implicit ec: ExecutionContext ): Future[U] =
fut.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map( f )
}
which implements the syntax your are looking for:
val future = Future{ 2 / 0 }
future.mapAll {
case Success(i) => i + 0.5
case Failure(_) => 0.0
}
Both map and flatMap variants:
implicit class FutureExtensions[T](f: Future[T]) {
def mapAll[Target](m: Try[T] => Target)(implicit ec: ExecutionContext): Future[Target] = {
val promise = Promise[Target]()
f.onComplete { r => promise success m(r) }(ec)
promise.future
}
def flatMapAll[Target](m: Try[T] => Future[Target])(implicit ec: ExecutionContext): Future[Target] = {
val promise = Promise[Target]()
f.onComplete { r => m(r).onComplete { z => promise complete z }(ec) }(ec)
promise.future
}
}
I want to flatten a Try[Option[T]] into a Try[T]
Here is my code
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
t match {
case f : Failure[T] => f.asInstanceOf[Failure[T]]
case Success(e) =>
e match {
case None => Failure[T](new Exception("Parsing error"))
case Some(s) => Success(s)
}
}
}
Is there a better way ?
You could try something like this which is a little neater:
val t = Try(Some(1))
val tt = t.flatMap{
case Some(i) => Success(i)
case None => Failure(new Exception("parsing error"))
}
More generically, this would be:
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
t.flatMap{
case Some(s) => Success(s)
case None => Failure(new Exception("parsing error"))
}
}
The trick is to convert the Option into Try for using flatmap.
Using getOrElse, you could also write:
def flattenTry[T](t: Try[Option[T]]): Try[T] = {
t flatMap { o => o map (Success(_)) getOrElse Failure(new Exception("parsing error")) }
}
You could make this even shorter, but possibly at the cost of functional purity (throwing is a side-effect) and performance (due to throwing/catching):
def flattenTry[T](t: Try[Option[T]]): Try[T] = {
Try(t.get getOrElse { throw new Exception("parsing error") })
}
One possible way is to use Try(o.get) to convert o: Option to o: Try.
This is very concise, but throws and catches exception when handling None, which might perhaps be a performance concern sometimes (or sometimes an ideological / code rules concern). Still, the code is so concise and well readable I think it is worth mentioning:
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
t.flatMap(o => Try(o.get))
}
Note: not that I recommend using it, but for completeness: even a shorter version is possible, which throws / catches even when Try is a failure:
def flattenTry[T](t: Try[Option[T]]) : Try[T] = {
Try(t.get.get)
}