Reputation: 57815
I have a webservice that I am calling asynchronously from scala. I want to match and handle some specific fault codes that can be returned by the webservice in a recover
block.
The error is returned as a SoapFault
instance that is wrapped in an additional exception so essentially I need to match all exceptions where
SoapFault
SoapFault
message matches what I wantI have this so far which is working but cumbersome:
call map { result =>
// handle success
} recover {
case e: Exception if e.getCause != null && e.getCause.isInstanceOf[SoapFault] && e.getCause.asInstanceOf[SoapFault].getMessage == "INVALID_INPUT" => {
// handle error
}
case e: Exception if e.getCause != null && e.getCause.isInstanceOf[SoapFault] && e.getCause.asInstanceOf[SoapFault].getMessage == "SERVER_BUSY" => {
// handle error
}
}
How can I do this in a better way with less repetition?
Upvotes: 1
Views: 158
Reputation: 57815
I have created my own extractor object that is similar to lmm's answer, but which extracts the error string (rather than checking it inside the extractor object) so that I can then match specific strings within the case expression.
Extractor:
object SoapFaultMessage {
def unapply(t: Throwable): Option[String] = {
if (t.getCause != null && t.getCause.isInstanceOf[SoapFault]) {
Some(t.getCause.asInstanceOf[SoapFault].getMessage)
} else {
None
}
}
}
Usage:
.. recover {
case SoapFaultMessage(msg) if msg == "INVALID_INPUT" => {
//handle
}
}
Upvotes: 0
Reputation: 21557
recover
block handles errors that were thrown during (i.e inside) Future
execution. As i understand from your question, although you are receiving a response which signals about some error, it doesn't throws any exception because the request itself was successful. It means that you need to handle your case inside with a flatMap
, something like this:
val response = call flatMap {
case SoapFault(error) => Future.failure(error)
// successful response
}
In this case you your response would be a failure, so now you can handle your error with a recover
block, but it's also not necessary, cause you can recover from your bad response inside flatMap
function, cause it also returns a Future
.
UPDATE
Like lmm
proposed you can use extractor with the same name, i.e:
object SoapFault {
def unapply(sf: SoapFault): Option[(Option[String], String)] =
Option((Option(sg.getCause), sf.getMessage))
}
Then deconstruct it in the block:
recover {
case SoapFault(None, "INVALID_INPUT") => // process
}
Upvotes: 1
Reputation: 17431
You could create your own Extractor Object. Something like (untested):
object FaultWithMessage {
def apply(message: String) = new Object() {
def unapply(t: Throwable): Boolean = t match {
case e: Exception if e.getCause != null &&
e.getCause.isInstanceOf[SoapFault] &&
e.getCause.asInstanceOf[SoapFault].getMessage == message => true
case _ => false
}
}
... recover {
case FaultWithMessage("INVALID_INPUT")() =>
//handle that one
case FaultWithMessage("SERVER_BUSY")() =>
//handle that one
...
}
Upvotes: 4