I'm writing a controller method in play framework that calls a function that returns a Future that may also throw an Exception. I'm having trouble figuring out how to catch and handle that Exception.
Here's what I tried:
def openIDCallback = Action { implicit request =>
Async (
Try(OpenID.verifiedId) match {
case Failure(thrown) => {
PurePromise(Ok("failed: " + thrown))
}
case Success(successResult) => {
successResult.map( userInfo => {
Ok(userInfo.id + "\n" + userInfo.attributes)
})
}
}
)
}
OpenID.verifiedId is the function from Play's OpenId api that returns Future[UserInfo]. Here's the source of that function:
def verifiedId(queryString: Map[String, Seq[String]]): Future[UserInfo] = {
(queryString.get("openid.mode").flatMap(_.headOption),
queryString.get("openid.claimed_id").flatMap(_.headOption)) match { // The Claimed Identifier. "openid.claimed_id" and "openid.identity" SHALL be either both present or both absent.
case (Some("id_res"), Some(id)) => {
// MUST perform discovery on the claimedId to resolve the op_endpoint.
val server: Future[OpenIDServer] = discovery.discoverServer(id)
server.flatMap(directVerification(queryString))(internalContext)
}
case (Some("cancel"), _) => PurePromise(throw Errors.AUTH_CANCEL)
case _ => PurePromise(throw Errors.BAD_RESPONSE)
}
}
As shown above, function can return PurePromise(throw Errors.AUTH_CANCEL) and PurePromise(throw Errors.BAD_RESPONSE). My attempt at solution handles successes correctly, but on exceptions I get:
play.api.Application$$anon$1: Execution exception[[AUTH_CANCEL$: null]]
My question is how do I catch and handle these exceptions in my controller method?
Handle the result of a future with methods like onComplete , or combinator methods like map , flatMap , filter , andThen , etc. The value in a Future is always an instance of one of the Try types: Success or Failure.
However, Scala doesn't actually have checked exceptions. When you want to handle exceptions, you use a try{...} catch{...} block like you would in Java except that the catch block uses matching to identify and handle the exceptions.
The Promise is a writable, single-assignment container that completes a Future. The Promise is similar to the Future. However, the Future is about the read-side of an asynchronous operation, while the Promise is about the write-side.
Await. result tries to return the Future result as soon as possible and throws an exception if the Future fails with an exception while Await. ready returns the completed Future from which the result (Success or Failure) can safely be extracted.
You should use recover
method of Future
instead of Try
like this:
Async (
OpenID.verifiedId.
map{userInfo => Ok(userInfo.id + "\n" + userInfo.attributes)}.
recover{ case thrown => Ok("failed: " + thrown) }
)
Try
can help you in case verifiedId
throws an exception instead of returning Future
. In your case verifiedId
successfully returns Future
(even if there will be an exception in this Future
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With