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.
Related
I am a newbie for Scala and now am trying to complete an exercise. How can I return an InvalidCartException while the function return type is Try[Price]
//Success: return the calculated price
//Failure: InvalidCartException
def calculateCartPrice(cart:Cart): Try[Price] = {
if(isCartValid(cart)) {
//Calculations happen here
return Try(Price(totalPrice));
}
}
def isCartValid(cart: Cart): Boolean = {
//THIS WORKS FINE
}
Thank you for the help
If you mean "how to make the Try contain an exception", then use the Failure() like below:
def calculateCartPrice(cart:Cart): Try[Price] = {
if(isCartValid(cart)) {
//Calculations happen here
Success(Price(totalPrice));
} else {
Failure(new InvalidCartException())
}
}
Then, given a Try you can use getOrElse to get the value of success or throw the exception.
Try will catch the exception for you, so put the code that can throw the exception in there. For example
def divideOneBy(x: Int): Try[Int] = Try { 1 / x}
divideOneBy(0) // Failure(java.lang.ArithmeticException: / by zero)
If what you have is a Try and you want to throw the exception when you have a Failure, then you can use pattern matching to do that:
val result = divideByOne(0)
result match {
case Failure(exception) => throw exception
case Success(_) => // What happens here?
}
The Neophyte's Guide to Scala has lots of useful information for people new to Scala (I found it invaluable when I was learning).
In the code below I have two Play for Scala functions, the first one catches an exception (this works fine) and in the second one I'm trying to rewrite it using Try.
I have two problems with Try: (1) when the number is negative the method doesn't fail, (2) I need to wrap all the responses with Future.successful.
How to fix this code?
class Test extends Controller {
def test1 = Action.async { request =>
val future = isPositive(-1)
future.map { result =>
Ok("OK, it's positive")
}
.recover {
case e => Ok(e.getMessage)
}
}
def isPositive(i: Int) = Future {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
def test2 = Action.async { request =>
isPositiveWithTry(-1) match {
case Success(s) => Future.successful(Ok("OK, it's positive (Try succeded)"))
case Failure(f) => Future.successful(Ok(f.getMessage + " (Try failed)"))
}
}
def isPositiveWithTry(i: Int) : Try[Future[Int]] = Try {
isPositive(i)
}
}
In isPositive method exceptions are already caught by Future
def isPositive(i: Int) = Future {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
In the below code
def isPositiveWithTry(i: Int) : Try[Future[Int]] = Try {
isPositive(i)
}
isPositive already catches all expections and Try is always a success.
So, when i is negative. Exception raised are handled by future and try gets a success value, resultant Try is a success. So you get successful Try with a failed Future inside.
Understanding using Grenade example
Assume throwing the exception as blowing up a Grenade.
Assume Future and Try as two layers. When grenade is blasted inside the double layer of Try[Future] i.e Try is around Future and grenade is gone off in the Future.
Now Future withstands the blast and becomes a failed value. As Future already took the damage caused by the damage of exception(grenade). Try will be a success but the value inside the Try is a failed future value. That failed future value is nothing but the exception raised.
Try is redundant when you are using Future
You can refactor your code to below one
Get rid of isPositiveWithTry. This method is not needed.
def isPositive(i: Int) = Future {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
def test2 = Action.async { request =>
isPositive(-1).flatMap { _ =>
Future.successful(Ok("OK, it's positive (Try succeded)"))
}.recoverWith {
case f: Throwable => Future.successful(Ok(f.getMessage + " (Try failed)"))
}
}
Again test2 can also be written as
def test2 = Action.async { request =>
isPositive(-1).map { _ =>
Ok("OK, it's positive (Try succeded)")
}.recover {
case f: Throwable => Ok(f.getMessage + " (Try failed)")
}
}
In case isPositive returns Try
def isPositive(i: Int) = Try {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
Now test2 will look like
def test2 = Action.async { request =>
isPositive(-1) match {
case Success(s) => Future.successful(Ok("OK, it's positive (Try succeded)"))
case Failure(f) => Future.successful(Ok(f.getMessage + " (Try failed)"))
}
}
Couple points:
1) You need to rewrite your isPositive such that it does not surround itself via a Future. The Future is catching the exception.
def isPositive(i: Int) ={
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
2) If you have a Try and you want a Future, then you can use the method on the companion object of Future, Future.fromTry. That will take a Try and turn it into the correct state of a Future.
I'm using Play framework by Scala. I have Postgresql database. It fetches data by following code:-
def eventById(id: Long): Option[EventRow] = {
val action = events.filter(_.id === id)
val results = db.run(action.result.head)
val notFound = None: Option[EventRow]
try {
Some(Await.result(results, Duration.Inf))
} catch {
case e: Exception => Logger.info(s"Failed to fetch event by id: $e.")
notFound
} finally {
}
}
}
Here in case data not bound it throws exception. Here I don't want to throw exception.I want to return notFound. I cannot even compile without throwing Exception.
Is there a way to return notFound if event not found in database?
Please let me know? Thanks!
Try:
def eventById(id: Long): Option[EventRow] = {
val action = events.filter(_.id === id)
val res: Future[Option[EventRow]] = db.run(action.result.headOption)
Await.result(res, Duration.Inf)
}
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
}
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.