I'm overriding a method in spray-json in order to catch an exception it throws. In one particular case I want to add special handling, but otherwise I want to rethrow the original exception.
But the exception isn't rethrowing.
object MyObject extends DefaultJsonProtocol {
override def fromField[T](value: JsValue, fieldName: String)(implicit reader: JsonReader[T]) = {
try {
super.fromField(value, fieldName)(reader)
} catch {
case e: DeserializationException =>
if (reader.isInstanceOf[SafeListFormat[_]]) EmptyList.asInstanceOf[T]
else deserializationError("Object is missing required member '" + fieldName + "'", e)
}
}
}
The deserializationError in spray-json: https://github.com/spray/spray-json/blob/master/src/main/scala/spray/json/package.scala
The method I'm overriding is fromField in here: https://github.com/spray/spray-json/blob/master/src/main/scala/spray/json/ProductFormats.scala
In debug mode I can see the original exception being caught, and my else case "rethrowing" the error, and even the deserializationError method being called in spray-json's library. But even through the DeserializationException is a RuntimeException the overridden method doesn't terminate.
I had wondered if there was something about deferred execution of the deserializationError method. But I even tried changing my exception handler from calling deserializationError to a simple throw e and that didnt work either.
What's going on here?
PS. I dont think this is specific to spray-json really, but is probably something interesting I dont know about scala. But I kept the example as a real world as possible just in case it is something particular to the way my overridden method is called by the spray-json library code.
EDIT: Raised same question with spray-user forum: https://groups.google.com/forum/#!topic/spray-user/YXtY6VyIVGk
It seem ok to me to be honest. So here go a few random observations (too long to put as comments):
Call super.fromField[T], right now you are not passing the T param. When things are weird, try to make everything explicit.
You can try functional error handling:
Try(super.fromField(value, fieldName)(reader)).recover {
case e: DeserializationException if (reader.isInstanceOf[SafeListFormat[_]]) => EmptyList.asInstanceOf[T]
case t: Exception => throw t
}.get
Note how I made the if part of the pattern match, doing that might help you insulate the problem.
I find it weird that your method does not terminate. You should probably try reducing the example to something very simple and start adding complexity little by little and see where it breaks.
Best of luck!
Related
I have a service class that gets some data from a database (for context, I'm using Play! Framework). Here's an example method:
def getAccessToken(id: BSONObjectID): Future[Option[String]] = {
userDAO.find(id).map {
case Some(user) =>
user.settings flatMap (_.accessToken)
case _ => None
}
}
I'm trying to improve the error handling (new to Scala) on this thing as there are a couple things that can go wrong:
User might not be found
User might be found but accessToken might not be set (accessToken is an Option[String])
As it stands right now, I can't differentiate between the two. My natural inclination to fix this is to use \/ from Scalaz and have the return type be Future[ErrorType \/ String] and this seems like a reasonable approach. In my controller method, I can for comprehension a bunch of different service methods like this by lifting into a wrapper monad.
But I have the following questions:
Should my ErrorType extend Exception, or should I just use the sealed trait style and just extend from that. I've heard that it is not good practice to use exceptions in Scala, so I'm not sure what the right approach is.
How can I handle logging without polluting the controller class with excessive log statements? If a controller class calls a bunch of these service methods, the controller will have to handle several different ErrorTypes in the for comprehension. Assuming I'm lifting all the monads to a wrapper monad with ?|, I want to avoid this:
accessToken <- service.getAccessToken(id) ?| { error => error match { case Error1 =>
logger.error(
"Unable to find access token for user: " + id
.toString())
InternalServerError(
ApiResponse("internal_server_error",
"Unable to get token."))
case Error2 => ...
}
Thanks!
I think Future[ErrorType / String] is a bit overkill as Future[T] already can hold either an object of type T or an Exception derived one (see Future.successful(...)/ Future.failed(...))
Should my ErrorType extend Exception, or should I just use the sealed trait style and just extend from that. I've heard that it is not good practice to use exceptions in Scala, so I'm not sure what the right approach is.
I would recommend to use a class (or a set of classes, one per particular error type), say YourAppException derived from Exception, as you need to handle low level exceptions one way or another anyway.
I agree that throwing/catching exceptions is not going very well with functional code and it is better to use Try[T] or Future[T] to return errors in a more explicit way instead. On the other hand there is nothing wrong with using an Exception derived class to hold some error info. It is often useful to wrap the original non-application (say IO) exception in an application one and keep a reference to the initial one in Exception's 'cause' for troubleshooting. It gives an opportunity to provide a more context specific error message.
How can I handle logging without polluting the controller class with excessive log statements?
Consider encapsulating error messages in Exception derived case classes, representing application errors so you can access the error messsages uniformly using exception.getMessage. It is easy to add some method to YourAppException to construct ApiResponse as well.
def getAccessToken(id: BSONObjectID): Future[String] = {
userDAO.find(id).flatMap {
case Some(user) =>
val optToken = user.settings.flatMap (_.accessToken)
optToken.map(Future.successful).getOrElse(Future.failed(AccessTokenIsInvalid(user)))
case _ => Future.failed(UserNotFoundError(user))
}
}
case class AccessTokenIsInvalid(user: String)
extends YourAppException(s"Access token is invalid for user $user") {
}
accessToken <- service.getAccessToken(id) ?| { error =>
logger.error(error.getMessage)
InternalServerError(
ApiResponse("internal_server_error", error.getMessage))
}
1) Yes, you are on a right way. The problem with exceptions is that when something fails it's hard to pattern-match on it to detect a reason.
I would do it like that:
sealed trait MyError
object UserNotFound extends MyError
object AuthFailed extends MyError
type MyResult = Either[MyError, String]
2) If a program is well-typed logging is necessary in places where information is lost.
If you deal with, for example, val x = Future[Either[Error, String]], then you haven't throttled potential error yet so logging is optional.
But when you somehow try to extract Either[MyError, String] from it you lose information so you should log it.
The same happens when you extract String from Either[MyError, String].
I have some code running inside Future.respond, that throws an NPE, because of a bug. The problem is that my unit tests totally missed it, and are all happily passing, because the NPE is swallowed by the RootMonitor.
So, my question is if there is any way to override the RootMonitor behavior for the unit tests to result in a test failure rather than swallowing the exception?
I know, I could just catch the exception inside respond, but that's kinda backwards - if I thought there could be an exception, I would've fixed it in the first place. That's exactly a kind of situation I would like my test to catch.
So, what I am looking for is a way to override the RootMonitor globally for the tests, or else to assert somehow that it handled no exceptions after the test finishes.
Is there a way to do something like this? How do people usually deal with this kind of tests?
Ok, I think, I found a solution. It seems a bit kludgy, so if someone can come up with a better way, please chime in, but here goes.
class MonitoredSuite extends FunSuite {
protected override def withFixture(test: NoArgTest): Outcome = {
var exception: Throwable = null
Monitor.using(Monitor.mk {
case e =>
exception = e
false
})(test()) match {
case x#Exceptional(_) => x
case s if exception == null => s
case _ => Exceptional(exception)
}
}
}
Basically, I install a noop monitor before each test, and then generate a failure if it was invoked.
Is it possible for an exception to be thrown, escaping the Future context?
Since a Future "evaluates" as soon as it's defined:
is it possible for the definition of a Future to throw an exception, passing through the Future context?
scala> Future { Thread.sleep(3000); println("3 seconds elapsed"); 100 }
res2: scala.concurrent.Future[Int] =
scala.concurrent.impl.Promise$DefaultPromise#56113384
scala> 3 seconds elapsed
I could not come up with such an example.
scala> Future { throw new Exception("Foo!") }
res3: scala.concurrent.Future[Nothing] =
scala.concurrent.impl.Promise$DefaultPromise#47a86fbb
Yes, but maybe not quite the way you're thinking of. According to the source, only errors that are not NonFatal will escape Future.apply.
try Success(body) catch { case NonFatal(e) => Failure(e) }
i.e. exceptions like: VirtualMachineError, OutOfMemoryError,StackOverflowError, ThreadDeath, LinkageError, InterruptedException, ControlThrowable.. will go uncaught as they represent a fatal JVM error that you will not be able to handle.
A future in itself does nothing except define the computation. It just so happens to be you're using one of the constructors (or apply methods) that, by default, begins running the computation immediately. The mixing of exception handling and concurrency is one of the issues that, unfortunately, not explicit with scala.concurrent.Future. A better alternative may be to use scalaz.concurrent.Task which combines error handling with explicit concurrency.
Why you want to throw an error from your future?
Future is a monad which will handles latency and exceptions while you are dealing with it.
If you look at Future implementation it looks like as below,
trait Future[T] { def onComplete(callback: Try[T] => Unit)(implicit exe..) }
So when as soon as your future gets complete and value available your callback method will be invoked and return unit.
If you see callback method you will get idea your result would be success or error and Try[T] woluld manage all the things for you.
Should my custom exception types be case classes?
On the plus side, I get extractors.
On the minus side, I get incorrect equality semantics. But I can avoid that by overriding equals.
So does it make sense, at a conceptual level, to make them case classes?
This is very subjective of course, but in my opinion it is good practice to have exception classes as case classes.
The main rationale being that when you catch an exception, you are doing pattern matching, and case classes are much nicer to use in pattern matching.
Here's an example that takes advantage of the ability to use the full power of pattern matching in a catch block, when using a case class exception:
object IOErrorType extends Enumeration {
val FileNotFound, DeviceError, LockedFile = Value
}
case class IOError(message: String, errorType: IOErrorType.Value) extends Exception(message)
def doSomeIO() { throw IOError("Oops, file not found!", IOErrorType.FileNotFound) }
try {
doSomeIO()
} catch {
case IOError( msg, IOErrorType.FileNotFound ) =>
println("File not found, please check the path! (" + msg + ")")
}
In this example, we have only one exception, but it contains an errorType field for when you want to know the exact error type that occurred (usually this is modelled through a hierarchy of exception, I'm not saying this is better or worse, the example is just illustrative). Because the IOError is a case class I can simply do case IOError( msg, IOErrorType.FileNotFound ) to catch the exception only for the error type IOErrorType.FileNotFound. Without the extractors that we get for free with case classes, I would have to catch the exception everytime, and then rethrow in case I'm actually not interested, which is definitely more verbose.
You say that case classes give you incorrect equality semantics. I don't think so. You, as the writer of the exception class gets to decides what equality semantics makes sense. After all when you catch an exception, the catch block is where you decide which exceptions to catch usually based on the type alone, but could be based on the value of its fields or whatever, as in my example. The point is that the equality semantics of the exception class has little to do with that.
One common idiom you lose by making exceptions case classes is the pattern of creating a subclass hierarchy of exceptions with subclassing used to indicate greater specificity of the error condition. Case classes can't be subclassed.
I like the answer from RĂ©gis Jean-Gilles. But if you have a good reason to not make a case class (see answer of Dave Griffith), you can archieve the same as in the sample above with a normal class and unapply:
object IOErrorType extends Enumeration {
val FileNotFound, DeviceError, LockedFile = Value
}
object IOError {
def unapply(err: IOError): Option[(String, IOErrorType.Value)] = Some(err.message, err.errorType)
}
class IOError(val message: String, val errorType: IOErrorType.Value) extends Exception(message)
def doSomeIO() { throw new IOError("Oops, file not found!", IOErrorType.FileNotFound) }
try {
doSomeIO()
} catch {
case IOError( msg, IOErrorType.FileNotFound ) =>
println("File not found, please check the path! (" + msg + ")")
}
I've read about and experimented with the Scala 2.9 try...catch feature, and it has me thinking about possibilities. What would I actually use it for other than saving a couple of lines of code?
Scala 2.9 Final Release Notes
The use case is to be able to have generic error handling throughout your application. Let's say you want to handle all FileNotFoundExceptions in your application by sending an e-mail to an administrator. Previously, you'd have to do it like this:
// Globally
val fileNotFound: PartialFunction[Throwable, Unit] = {
case e: FileNotFoundException =>
// Create report and send the e-mail
}
// On each try-catch-block
try {
// Open file
}
catch {
case fnf: FileNotFoundException => fileNotFound(fnf)
}
Now you just do:
try {
// Open file
} catch fileNotFound
This also has the nice advantage that you can link several such exception handlers using the orElse method on partial functions:
val fileErrors = fileNotFound orElse endOfFile orElse invalidFormat
And then just use that everywhere where you need file exception handling. Such an error handler can be dynamically combined based on the configuration file for the application, for example. This is much less cumbersome than pattern matching everywhere and calling the correct handler.
One useful thing which could be pimped on top of partial functions is the andAlso operator, which acts as a sequencing operator on two partial functions. This would be useful when you want to do some error handling specific to a particular try-catch block after having done the generic error handling.
implicit def pf2ops(pf: PartialFunction[Throwable, Unit]) = new {
def andAlso(localpf: PartialFunction[Throwable, Unit]) = new PartialFunction[Throwable, Unit] {
def apply(t: Throwable) = {
if (pf.isDefinedAt(t)) pf(t)
localpf(t)
}
def isDefinedAt(t: Throwable) = pf.isDefinedAt(t) || localpf.isDefinedAt(t)
}
}
And then you can do this:
scala> try {
| throw new java.io.FileNotFoundException
| } catch fnf andAlso {
| case e: Exception => println("I don't know, but something is specific to this particular block.")
| }
I don't know, but something is specific to this particular block.
I guess you could play further with the exact semantics and the meaning (and the name) of andAlso.
Good answer by axel22, but I think the real reason for its introduction is something else. The try/catch/finally handling introduced a special case. You used a partial function literal, but you could not actually replace that with a partial function. Now, catch just receive a partial function, and one more special case in the language is gone.