Custom Exception in scala
ScalaExceptionScala Problem Overview
how can i create custom exceptions in Scala extending Exception
class and throw them when exception occurs as well as catch them.
example in java :
class CustomException extends Exception {
public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT";
}
Scala Solutions
Solution 1 - Scala
final case class CustomException(private val message: String = "",
private val cause: Throwable = None.orNull)
extends Exception(message, cause)
Just try catch:
try {
throw CustomException("optional")
} catch {
case c: CustomException =>
c.printStackTrace
}
Solution 2 - Scala
class MyException(message: String) extends Exception(message) {
def this(message: String, cause: Throwable) {
this(message)
initCause(cause)
}
def this(cause: Throwable) {
this(Option(cause).map(_.toString).orNull, cause)
}
def this() {
this(null: String)
}
}
This is almost identical to @Jacek L.'s answer. I just wanted to add some more input on the motive behind this answer.
Why so many constructors?
Throwable
is written in kind of a funny way. It has 4 constructors
-- ignoring the one with the boolean
toggles -- each of them behaves a bit differently with null
s, and these differences could only be maintained with multiple constructors.
It would have been a bit cleaner if Scala would have allowed to call a superclass constructor via super
, but it doesn't :(
Why not a case class?
- Perfectly maintaining the constructors' behavior regarding
null
s wouldn't be possible; specifically, bothdef this()
anddef this(message: String)
will have to set thecause
tonull
, while originally it is set tothis
. toString
will not be overridden.- The message and the cause are already publicly available via
getMessage
andgetCause
. Adding another reference to these is redundant. equals
will be overridden and will behave differently.
Meaning,new Exception("m") == new Exception("m") // false
whilenew CaseException("m") == new CaseException("m") // true
If one desires to access the message and the cause via pattern-matching, one can simply implement the unapply
method:
object MyException {
def unapply(e: MyException): Option[(String,Throwable)] = Some((e.getMessage, e.getCause))
}
Solution 3 - Scala
You might want to create a sealed trait:
sealed trait MyException {
// This is called a "self annotation". You can use "self" or "dog" or whatever you want.
// It requires that those who extend this trait must also extend Throwable, or a subclass of it.
self: Throwable =>
val message: String
val details: JsValue
}
Then you can have as many case class
es as you need extending not only Exception
, but your new trait.
case class CustomException(message: String) extends Exception(message) with MyException {
override val details: JsValue = Json.obj("message" -> message, "etc" -> "Anything else")
}
Now, the whole point of using Scala is walking towards a more functional programming style, it will make your app more concurrent, so if you need to use your new custom exception, you might want to try something like this:
def myExampleMethod(s: Option[String]): Future[Boolean] = Try {
s match {
case Some(text) =>
text.length compareTo 5 match {
case 1 => true
case _ => false
}
case _ => throw CustomException("Was expecting some text")
}
}
match {
case Success(bool) => Future.successful(bool)
case Failure(e) => Future.failed(e)
}
Solution 4 - Scala
In order to reflect all the original constructors from Exception I'd implement a custom exception with the following pattern:
class CustomException(msg: String) extends Exception(msg) {
def this(msg: String, cause: Throwable) = {
this(msg)
initCause(cause)
}
def this(cause: Throwable) = {
this(Option(cause).map(_.toString).orNull)
initCause(cause)
}
def this() = {
this(null: String)
}
}
This can be also achieved with a trait as mentioned in previous answer. I'd just not create individual classes in this case:
trait SomeException { self: Throwable =>
def someDetail: SomeDetail
}
then, when throwing:
throw new Exception(...) with SomeException {
override val someDetail = ...
}
and when matching:
try {
...
} catch {
case ex: Throwable with SomeException =>
ex.getCause
ex.getMessage
ex.someDetail
}
The advantage here is that you are not sticking to any particular constructor of the parent exception.
something more or less like that.
Solution 5 - Scala
You define your custom exception like this
case class CustomException(s: String) extends Exception(s)
And you can throw your exception like this:
try{
...
} catch{
case x:Exception => throw new CustomException("whatever")
}
Solution 6 - Scala
Similar to other answers, but I prefer to use a companion object instead of alternate constructors.
class MyException(message: String, cause: Throwable = null) extends Exception(message, cause)
object MyException {
def apply(message: String): MyException = new MyException(message)
def apply(message: String, cause: Throwable): MyException = new MyException(message, cause)
}
Solution 7 - Scala
Adding to all the answers above, If at all you want to have an error hierarchy, abstract class would help.
abstract class GenericError(message: String) extends Exception(message)
case class SpecificErrorA(message: String) extends GenericError(message)
case class SpecificErrorB(message: String) extends GenericError(message)
throw new SpecificErrorA("error on A") // OR
throw new SpecificErrorB("error on B")
The same is possible using a trait instead of an abstract class, but they are limited in that they do not have constructor parameters.
Probably use GenericError everywhere and deconstruct (pattern match) it on the application/controller boundary.