Matching on nested exception type - scala

I am using some client library and had some code that ignored a specific exception using scala.util.control.Exception.ignoring:
ignoring(classOf[ReallyNotThatExceptionalException]) {
stuff()
}
Now that library changed to wrap all exceptionn in another exception class, which forced me to change my code to this:
try { stuff() }
catch {
case e:WrapperException if e.getCause != null && e.getCause.isInstanceOf[ReallyNotThatExceptionalException] => { }
}
So what I'm looking for a more readable way to express "catch exceptions that are caused by".

0__'s answer is good, but it would be better if you were not forced to write a specific object (CausedByFoo) for each potential exception.
As it happens, there is not much to change to end up with a generic CausedBy helper object:
class Foo(message: String) extends Exception(message)
class Bar(cause: Throwable) extends Exception(cause)
object CausedBy {
def unapply(e: Throwable): Option[Throwable] = Option(e.getCause)
}
def test(block: => Unit): String =
try {
block
"ok"
} catch {
case CausedBy(ex: Foo) => "not ok: " + ex.getMessage
}
test(println("hello"))
test(println("hello".toInt)) // uncaught exception
test(throw new Bar(new Foo("Ooops, foo error!"))) // caught
As should be obvious, you can use CausedBy with any exception (by example by doing case CausedBy(ex: Baz).
You can even nest it to handle an exception caused by an exception caused by an exception (by doing something like case CausedBy(CausedBy(ex: Foo))

The catch block can handle any regular pattern match, so
class Foo extends Exception
class Bar(cause: Exception) extends Exception(cause)
object CausedByFoo {
def unapply(e: Exception): Boolean = e.getCause match {
case _: Foo => true
case _ => false
}
}
def test(block: => Unit): String =
try {
block
"ok"
} catch {
case CausedByFoo() => "not ok"
}
test(println("hello"))
test(println("hello".toInt)) // uncaught exception
test(throw new Bar(new Foo)) // caught

I tweaked Régis' answer to allow matching against both outer and inner exception type.
trait CausedBy[T <: Throwable] {
def unapply(e: T): Option[Throwable] = Option(e.getCause)
}
object IOExceptionCausedBy extends CausedBy[IOException]
Then you can match like this:
try {
// do some DB thing
} catch {
case IOExceptionCausedBy(exception: PSQLException) =>
// handle PSQL exception
}

Related

When a scala recover should be used:

I have a simple flow of orders from an controller to services back to the controller, and im trying to make sure I use future recovers in the right place and in general to cover exceptions properly.
controller action:
def getSiblings(): Action[JsValue] = Action.async(parse.json) { request =>
request.body.validate[Person] match {
case JsSuccess(person, _) =>
peopleService.getSiblings(person).map(res => Ok(Json.toJson(res))) recover {
case t: Throwable =>
logger.error("error running getSiblings: ", t)
InternalServerError
}
case JsError(errors) => Future(BadRequest(s"not a good person format ${errors.mkString}"))
}
}
peopleService:
class PeopleService #Inject() extends LazyLogging {
def getSiblings(personToGetSiblings: Person): Future[List[SiblingResults]] = {
// isSibling is a method of a person that returnes a future and can fail
Future.sequence(listOfPeople.map(person => person.isSibling(personToGetSiblings))) recover {
case e: Exception => {
throw new RuntimeException("fail to get siblings with error: ", e)
}
}
}
}
case class SiblingResults (person: Option[Person])
and a Person:
#Singleton
class PersonA #Inject() (configuration: Configuration, peopleApi: PeopleApi) extends Person {
def isSibling(personToMatch: Person): Future[SiblingResults] = {
val res = for {
// areSiblings returnes a Future[Boolean]
areThey <- peopleApi.areSiblings(personToMatch, personInstance) recover {
case ex: Exception => throw new Exception("PeopleApi failed")
}
} yield areThey
if (res) Some(personInstance) else None
}
val personInstance = this
...
}
what will be the right way to recover those futures?
Use Play's Action composition to handle any failures. This your code would be clean handling only the business logic without the extra plumbing stuff like exception handling etc. You let the exceptions bubble up to the controller and exception is handled finally by the ActionBuilder.
ActionBuilder
import play.api.libs.json.Json
import play.api.mvc.{ActionBuilder, Request, Result}
import play.api.mvc.Results.Status
import scala.concurrent.Future
/**
* Created by chlr on 12/2/16.
*/
object ErrRecoveryAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: Request[A] => Future[Result]) = {
block(request) recover errorHandler
}
def errorHandler: PartialFunction[Throwable, Result] = {
// you can apply a different statuscode other than 500 depending on the type of exception matched.
case th: Throwable =>
new Status(500).apply(Json.obj("error_message" -> th.getMessage, "error_class" -> th.getClass.getName))
}
}
Controller usage:
Note how there is no exception handling in the controller and furthermore no exception handling is required in other service classes.
def getSiblings(): Action[JsValue] = ErrRecoveryAction.async(parse.json) {
request =>
peopleService
.getSiblings(request.body.as[Person])
.map(res => Ok(Json.toJson(res)))
}

How to add logging to try/catch with the borrowing pattern

How can I add logging in the case of an exception in the code below?
I tried to add a catch, but then I get an error saying that Unit does not conform to the type T.
Is there a trick around this somehow?
private def withClient[T](body: Jedis => T): T = {
var jedis: Jedis = null
try {
jedis = pool.getResource
body(jedis)
}
catch {
case _ => println("hllo")
}
finally {
if(jedis != null) jedis.close()
}
}
The problem is that in the case of an exception you are returning the value of println("hllo") which is Unit
You need to change the return type to something that represents the fact that you may not have a value, I'd suggest Try[T] or if you don't care to carry the exception data out of the function you could use Option[T]
private def withClient[T](body: Jedis => T): Try[T] = {
var jedis: Jedis = null
Try(
try {
jedis = pool.getResource
body(jedis)
}
catch {
case e =>
println("hllo")
throw e
}
finally {
if(jedis != null) jedis.close()
}
)
}
or
private def withClient[T](body: Jedis => T): Option[T] = {
var jedis: Jedis = null
try {
jedis = pool.getResource
Some(body(jedis))
}
catch {
case e =>
println("hllo")
None
}
finally {
if(jedis != null) jedis.close()
}
}
If your body function throws an exception instead of returning a T,
there's pretty much nothing you can do--you have to propagate the
exception forward instead of returning a T from withClient. Try is
the right approach to handle this because it safely captures the
exception and allows you to do something only if there was an exception
thrown. E.g.,
private def withClient[T](body: Jedis => T): T = {
val jedis = pool.getResource
val tryT = scala.util.Try(body(jedis))
jedis.close()
tryT.failed foreach { e => println(e.getMessage) }
tryT.get
}
The following points are notable:
We got rid of null and var
We don't need to worry about pool.getResource throwing an exception
because if it does, we can't go ahead anyway and we don't have to
worry about closing the resource because the exception means it was
never opened in the first place.
We make sure we close the jedis resource regardless of exception
because if there was an exception, it would've been safely caught in
the Try
We print a message only if there is any exception
We 'force' a value using Try#get only if there was no exception, and
if there was an exception, it will get rethrown here.

How do I get hold of exceptions thrown in a Scala Future?

I've been working up my answer to Is there a standard Scala function for running a block with a timeout?, and have run into a problem if an exception is thrown in a Future.
def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = {
awaitAll(timeoutMs, future(f)).head.asInstanceOf[Option[T]]
}
So that
runWithTimeout(50) { "result" } should equal (Some("result"))
runWithTimeout(50) { Thread.sleep(100); "result" } should equal (None)
But if I throw an exception in my block it doesn't leak, but is swallowed - so that the following fails with "..no exception was thrown"
intercept[Exception] {
runWithTimeout(50) { throw new Exception("deliberate") }
}.getMessage should equal("deliberate")
Syserr has a stack trace with the message
<function0>: caught java.lang.Exception: deliberate
but I can't find where in the Scala runtime that is printed.
Apart from wrapping f in another block which catches exceptions and propagates them if thrown, is there any way to persuade awaitAll and/or Future to throw?
Short answer: no.
Exceptions don't do what you want when you're working in a threaded context, because you want to know about the exception in the caller, and the exception happens in the future's thread.
Instead, if you want to know what the exception was, you should return an Either[Exception,WhatYouWant]--of course, you have to catch that exception within the future and package it up.
scala> scala.actors.Futures.future{
try { Right("fail".toInt) } catch { case e: Exception => Left(e) }
}
res0: scala.actors.Future[Product with Serializable with Either[Exception,Int]] = <function0>
scala> res0() // Apply the future
res1: Product with Serializable with Either[Exception,Int] =
Left(java.lang.NumberFormatException: For input string: "fail")
Disclaimer: I work for Typesafe
Or.... you could use Akka and it would give you what you want without you having to go through hoops for it.
val f: Future[Int] = actor !!! message
Then
f.get
Will throw the exception that happened in the actor
f.await.exception
will give you an Option[Throwable]
Working my way through #Rex Kerr's suggestion, I've created
object Timeout {
val timeoutException = new TimeoutException
def runWithTimeout[T](timeoutMs: Long)(f: => T) : Either[Throwable, T] = {
runWithTimeoutIgnoreExceptions(timeoutMs)(exceptionOrResult(f)) match {
case Some(x) => x
case None => Left(timeoutException)
}
}
def runWithTimeout[T](timeoutMs: Long, default: T)(f: => T) : Either[Throwable, T] = {
val defaultAsEither: Either[Throwable, T] = Right(default)
runWithTimeoutIgnoreExceptions(timeoutMs, defaultAsEither)(exceptionOrResult(f))
}
def runWithTimeoutIgnoreExceptions[T](timeoutMs: Long)(f: => T) : Option[T] = {
awaitAll(timeoutMs, future(f)).head.asInstanceOf[Option[T]]
}
def runWithTimeoutIgnoreExceptions[T](timeoutMs: Long, default: T)(f: => T) : T = {
runWithTimeoutIgnoreExceptions(timeoutMs)(f).getOrElse(default)
}
private def exceptionOrResult[T](f: => T): Either[Throwable, T] =
try {
Right(f)
} catch {
case x => Left(x)
}
}
so that
#Test def test_exception {
runWithTimeout(50) { "result" }.right.get should be ("result")
runWithTimeout(50) { throw new Exception("deliberate") }.left.get.getMessage should be ("deliberate")
runWithTimeout(50) { Thread.sleep(100); "result" }.left.get should be (Timeout.timeoutException)
runWithTimeout(50, "no result") { "result" }.right.get should be ("result")
runWithTimeout(50, "no result") { throw new Exception("deliberate") }.left.get.getMessage should be ("deliberate")
runWithTimeout(50, "no result") { Thread.sleep(100); "result" }.right.get should be ("no result")
}
Again, I'm a bit of a Scala novice, so would welcome feedback.
scala.concurrent.ops.future includes exception handling.
So, instead of importing scala.actors.Futures.future, import scala.concurrent.ops.future instead.
That simple change in which import is there will cause the caller's call to .get to rethrow the exception. It works great!
Or use Future.liftTryTry, turns it from Future[Object] to Future[Try[Object]], and you can match on the Try[Object] and check for an exception case Throw(e) and log / exit gracefully
You need to override the method exceptionHandler in order to catch exceptions. So your option is to define your own future method so it creates a MyFutureActor with exceptionHandler.
EDIT: FutureActor is private, so subclassing it isn't possible.
Another option is to use links to know when exceptions happened.
However, I think Rex Kerr's approach is better - just wrap the function in something that will catch the Exception. Too bad future doesn't already do that.

How to catch an exception within loop/react of an actor?

Is it possible to catch an exception raised within behaviour? Where to place the try/catch? I know that react uses exceptions to reuse the same thread for different actors and that´s why I don´t know where to put the try/catch. I want to catch certain exceptions by myself for logging.
import scala.actors._
def behaviour: PartialFunction[Any,Unit] = {
case x =>
println(x)
throw new IllegalStateException
}
val a = new Actor {
def act {
loop {
react {
behaviour
}
}
}
}
a.start
a ! "Bam"
eThe Actor has a exception handler function which can be overridden:
override def exceptionHandler = {
case e: Exception =>
println(e.getMessage())
}
Whenever a exception is raised in the actor that would normally cause it to terminate - the exceptionHandler partial function is applied to the exception.
Edit
With Exception filter:
class ExceptionalActor extends Actor{
def act() {
loop {
react {
case "bad" => throw new NoSuchFieldException("Bad Message")
case "impossible" => throw new Exception("Impossible Exception")
case m => println("non-bad message " + m )
}
}
}
override def exceptionHandler = {
case e: NoSuchFieldException => println("handled " + e.getMessage() )
}
}
object Tester extends App {
val eActr = new ExceptionalActor
eActr start
eActr ! "any message1"
eActr ! "bad"
eActr ! "any message2"
eActr ! "impossible"
eActr ! "any message3"
}
produces:
non-bad message any message1
handled Bad Message
non-bad message any message2
org.scratch.act.ExceptionalActor#7f5663a2: caught java.lang.Exception: Impossible Exception
:
And actor death.
ref: Actors in Scala

Better syntax for Scala anonymous function?

Experimenting with Scala... I'm trying to define something analogous to the "#" hack in PHP (which means, ignore any exception in the following statement).
I managed to get a definition that works:
def ignoreException(f: () => Unit) = {
try {
f();
}
catch {
case e: Exception => println("exception ignored: " + e);
}
}
And use it like this:
ignoreException( () => { someExceptionThrowingCodeHere() } );
Now here is my question... Is there anyway I can simplify the usage and get rid of the () =>, and maybe even the brackets?
Ultimately I'd like the usage to be something like this:
`#` { someExceptionThrowingCodeHere(); }
# is reserved in Scala (for pattern matching), but would you accept ##?
scala> def ##(block: => Unit): Unit = try {
block
} catch {
case e => printf("Exception ignored: %s%n", e)
}
$at$at: (=> Unit)Unit
scala> ## {
println("before exception")
throw new RuntimeException()
println("after exception")
}
before exception
Exception ignored: java.lang.RuntimeException
I'm not convinced this is a good idea, however ☺
You don't have to use a function as your parameter, a "by-name" parameter will do:
def ignoreException(f: =>Unit) = {
try {
f
}
catch {
case e: Exception => println("exception ignored: " + e)
}
}
ignoreException(someExceptionThrowingCodeHere())
Eric.