Custom Exception in scala

ScalaException

Scala 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 nulls, 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 nulls wouldn't be possible; specifically, both def this() and def this(message: String) will have to set the cause to null, while originally it is set to this.
  • toString will not be overridden.
  • The message and the cause are already publicly available via getMessage and getCause. Adding another reference to these is redundant.
  • equals will be overridden and will behave differently.
    Meaning, new Exception("m") == new Exception("m") // false
    while new 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 classes 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNileshView Question on Stackoverflow
Solution 1 - ScalaAndrzej JozwikView Answer on Stackoverflow
Solution 2 - ScalaEyal RothView Answer on Stackoverflow
Solution 3 - ScalaMesi RendónView Answer on Stackoverflow
Solution 4 - ScalaJacek L.View Answer on Stackoverflow
Solution 5 - ScalahminleView Answer on Stackoverflow
Solution 6 - ScalaDef_OsView Answer on Stackoverflow
Solution 7 - ScalaGagandeep KalraView Answer on Stackoverflow