I'm using util.control.Exception.catching to convert internal exceptions into an exception type specific to my library:
import util.control.Exception._
abstract class MyException extends Exception
case class ErrorOccurredDuringFoo(e : Exception) extends MyException
def foo : Foo = {
catching(classOf[Exception]) either { fooInternals } match {
case Left(e) => throw ErrorOccurredDuringFoo(e)
case Right(v) => v
}
}
Unfortunately, this doesn't work. Applying the Catch returned by either doesn't return Either[Exception,Foo], it returns Either[Throwable,Foo]. But I've already told catching I want it to catch only subtypes of Exception, not all Throwables, and internally it's already matched an Exception.
Am I using this correctly? Is there no way I can convince catching to return the exception it catches as an instance of the class of exceptions I asked it to catch? Is my best bet to just add a redundant asInstanceOf[Exception]? I'd rather not if I can avoid it, as the catching instance could logically be created elsewhere, and I'd like to get a compile error if I one day change it to catching[Throwable] without changing ErrorOccurredDuringFoo, not a runtime error when the cast to Exception fails.
Catch isn't parameterised on Throwable, only on the result type. The only way to downcast the Throwable type is with the mkCatcher method:
val c = catching[Foo](
mkCatcher(
(t: Throwable) => t.getClass == classOf[MyException],
(e: MyException) => throw new ErrorOccurredDuringFoo(e)))
c(fooInternals)
But, Catch takes a Catcher[T] – which is really just an alias for a PartialFunction[Throwable, T].
As a case statement is a PartialFunction we can use pattern matching:
val c: Catcher[Foo] = {
case e: MyException => throw new ErrorOccurredDuringFoo(e)
}
catching(c)(fooInternals)
You could write it like this:
def foo : Foo = {
catching(classOf[Exception]) either { fooInternals } match {
case Left(e: Exception) => throw ErrorOccurredDuringFoo(e)
case Right(v) => v
}
}
It is interesting that it doesn't complain about missing cases.
Related
Because Kotlin doesn't support multiple catch like java does, I want to create extension to partially solve the problem.
fun <T: Throwable> (() -> Unit).catch(vararg exceptions: KClass<T>, catchBlock: (Throwable) -> Unit) {
try {
this()
} catch (e: Throwable) {
if (e::class in exceptions) catchBlock(e) else throw e
}
}
That can be called like this:
{
throw NotImplementedException.exception()
}.catch(NotImplementedException::class) {
//handle it
}
But the problem is that if to pass several arguments with different types it doesn't work (Type inference failed):
{
throw IndexOutOfBoundsException()
}.catch(NotImplementedException::class, IndexOutOfBoundsException::class) {
}
So how can I change signature of the extension to catch several exceptions of different types?
Let's look at the types of the two arugments you're trying to pass to your function:
val kclass1: KClass<NotImplementedException> = NotImplementedException::class
val kclass2: KClass<IndexOutOfBoundsException> = IndexOutOfBoundsException::class
While they are both KClass instances, their type parameters are different - NotImplementedException and IndexOutOfBoundsException. This means that no generic T type parameter can be found for the function that would fit both of these types exactly.
Just for demonstration and explanation purposes, you could help type inference by casting both of your types to KClass<Throwable> (or KClass<Exception>, or KClass<RuntimeException, you get the idea) yourself, that way it could figure out the generic type:
{
throw IndexOutOfBoundsException()
}.catch(NotImplementedException::class as KClass<Throwable>, IndexOutOfBoundsException::class as KClass<Throwable>) {
println("Caught something: $it")
}
But the real solution is to use the out keyword to specify use-site variance for the type parameter of the KClass instances:
fun <T : Throwable> (() -> Unit).catch(vararg exceptions: KClass<out T>, catchBlock: (Throwable) -> Unit) {
try {
this()
} catch (e: Throwable) {
if (e::class in exceptions) catchBlock(e) else throw e
}
}
This way the compiler will find a type for T that's both a subtype of Throwable as specified, and is a supertype of all argument's KClass type parameters - this will be RuntimeException in this case, which you can find out by opening intention actions on the catch call (Alt + Enter on Windows, ⌥↩ on macOS) and choosing Add explicit type arguments. This will produce the following:
{
throw IndexOutOfBoundsException()
}.catch<RuntimeException>(NotImplementedException::class, IndexOutOfBoundsException::class) {
println("Caught something: $it")
}
I am in the processing of learning Kotlin and ran into a problem I couldn't figure out.
I would like to extend the Java class RuntimeException in Kotlin and be able to use any one of three of its constructors, in different circumstances (based on what info I have at the time I want to throw an exception). In java my class would look like this:
public class PhotoLibException extends RuntimeException {
public PhotoLibException(String message, RuntimeException ex) {
super(message, ex);
}
public PhotoLibException(String message) {
super(message);
}
public PhotoLibException(RuntimeException ex) {
super(ex);
}
}
When I try to do this in Kotlin, I used this answer as a guide: Kotlin secondary constructor however, I had a problem trying to figure out how to invoke the appropriate super constructor correctly. For example, using functions seemed to be a good approach, like this:
fun PhotoLibException(message: String): PhotoLibException {
val ex = null
return PhotoLibException(message, ex)
}
fun PhotoLibException(ex: Exception): PhotoLibException {
val message = ""
return PhotoLibException(message, ex)
}
class PhotoLibException(message: String, ex: Exception?): RuntimeException(message, ex) {
}
However, in this Kotlin example above, I am always invoking the super constructor with two args, and not invoking the constructor most appropriate to the situation. So what I have above works, but doesn't do exactly what it would do in Java where a different constructor is invoked in each situation.
I also tried instantiating a new RuntimeException inside each fun above and casting it to PhotoLibException, but I wasn't allowed to do that.
Can anyone suggest how I would do this correctly in Kotlin?
Update: Since M11 (0.11.*), you can use secondary constructors to solve this problem:
class PhotoLibException : RuntimeException {
constructor(message: String, ex: Exception?): super(message, ex) {}
constructor(message: String): super(message) {}
constructor(ex: Exception): super(ex) {}
}
Currently, there's no way to call different super-constructors in different context from the same class. It will be supported in the upcoming months, though.
Use the #JvmOverloads annotation.
class PhotoLibException: RuntimeException {
#JvmOverloads constructor(message: String, ex: Exception?)
}
I have some models in a Play! application that I would like to serialize/deserialize to and from JSON. I used to have separate methods for that, but I have seen that the preferred way is to give an implicit instance of Formats[T] or Reads[T], like
import play.api.libs.json.{ JsValue, Reads }
case class Foo(bar: Int, ...)
object Foo {
implicit object FooReads extends Reads[Foo] {
def reads(json: JsValue): Foo = //whatever
}
}
Now, it may happen that the model has the correct fields in the JSON, but it does not validate. In this case, I am not able to deserialize - I should get an exception when using json.as[Foo] or None when using json.asOpt[Foo].
If I throw an exception when I find a field that does not validate, everything seems to work as expected. But I took the care of trying to find out what exception I should throw, and in the source for JsValue I found this
def asOpt[T](implicit fjs: Reads[T]): Option[T] = fjs.reads(this).fold(
valid = v => Some(v),
invalid = _ => None
).filter {
case JsUndefined(_) => false
case _ => true
}
Now, I cannot understand how this is supposed to work. The implicit instance of fjs is supplied by myself in the companion object, so I know that fjs.reads(this) either returns a Foo or throws an exception.
Where is this fold coming from? It certainly is not a method on Foo. I guess one could have an implicit conversion, but it should be from Any to something with a fold method, so it could not be of much interest. Even worse, if fjs.reads(this) throws an exception, there is nothing to catch it!
So, how should one handle invalid input in the JSON in an instance of Reads[T]? And how does the mechanism above actually work?
Looking at JsonValue.scala in Play 2.0.x:
def asOpt[T](implicit fjs: Reads[T]): Option[T] = catching(classOf[RuntimeException]).opt(fjs.reads(this)).filter {
case JsUndefined(_) => false
case _ => true
}
In fact the code is using scala.util.control.Exception.catching[T](exceptions: Class[_]*): Catch[T], which returns a Catch[T]. Then it calls opt(...) on it. If an exception is thrown, then it will return a None instead of an instance of T.
So, when you get an error deserializing, you can safely throw an exception.
I've recently seen code like this:
val maybeInt = catching(classOf[NFE]) opt arg.toInt
What is this opt? An Option? Why isn't it using getOrElse to extract the value? In the above code, will maybeInt be None if a NumberFormatException gets thrown?
catching looks like it's some sort of method call, doesn't it? It is, but it actually returns an instance of a class Catch; it doesn't directly take an argument. This class has two methods that are particularly useful for dealing with exceptions (and several more for catching multiple exceptions). The first is
def opt [U >: T] (body: ⇒ U) : Option[U]
which is being used here--you give it something that may throw an exception, and it will return Some(result) if everything went okay, and None if the targeted exception was caught:
scala> type NFE = NumberFormatException
defined type alias NFE
scala> import scala.util.control.Exception._
import scala.util.control.Exception._
scala> catching(classOf[NFE]).opt( "fish".toInt )
res0: Option[Int] = None
scala> catching(classOf[NFE]).opt( "42".toInt )
res1: Option[Int] = Some(42)
You can then deal with this with map or filter or getOrElse or whatever else you use to deal with options.
The other useful method is either, which returns an instance of Left(exception) if an exception was thrown, and a Right(result) if it was not:
scala> catching(classOf[NFE]).either( "fish".toInt )
res2: Either[Throwable,Int] = Left(java.lang.NumberFormatException: For input string: "fish")
scala> catching(classOf[NFE]).either( "42".toInt )
res3: Either[Throwable,Int] = Right(42)
You can then use fold or map to an option or whatever else you like doing with eithers.
Note that you can define a single catcher and use it multiple times (so you don't need to create the catcher object every time you, for example, parse an integer):
scala> val catcher = catching(classOf[NFE])
catcher: util.control.Exception.Catch[Nothing] = Catch(java.lang.NumberFormatException)
scala> catcher.opt("42".toInt)
res4: Option[Int] = Some(42)
scala> catcher.opt("fish".toInt)
res5: Option[Int] = None
Edit: as Daniel points out in the comments, this still creates a temporary Catch[Option]; given the method signatures, there isn't an easy way to just have it trap exceptions and generate options without creating any extra objects. This reminds me why I write my own methods to do exactly that:
def optNFE[T](t: => T) = try { Some(t) } catch {case nfe: NFE => None}
optNFE( "fish".toInt ) // gives None
optNFE( "42".toInt ) // gives Some(42)
I use a more simple pattern when there is only one catch :
try{
return args.split(" ").exists(line.startsWith _)
}catch {
case _ =>{//generic exception
logger.error("Error with line ${line} for ${ex.message}")
throw _
}
}
I'm definitely not yet a Scala pro, and I guess you could find shorter stuff
I'm using ScalaTest for testing some Scala code.
I currently testing for expected exceptions with code like this
import org.scalatest._
import org.scalatest.matchers.ShouldMatchers
class ImageComparisonTest extends FeatureSpec with ShouldMatchers{
feature("A test can throw an exception") {
scenario("when an exception is throw this is expected"){
evaluating { throw new Exception("message") } should produce [Exception]
}
}
}
But I would like to add additional check on the exception, e.g. I would like to check that the exceptions message contains a certain String.
Is there a 'clean' way to do this? Or do I have to use a try catch block?
I found a solution
val exception = intercept[SomeException]{ ... code that throws SomeException ... }
// you can add more assertions based on exception here
You can do the same sort of thing with the evaluating ... should produce syntax, because like intercept, it returns the caught exception:
val exception =
evaluating { throw new Exception("message") } should produce [Exception]
Then inspect the exception.
If you need to further inspect an expected exception, you can capture it using this syntax:
val thrown = the [SomeException] thrownBy { /* Code that throws SomeException */ }
This expression returns the caught exception so that you can inspect it further:
thrown.getMessage should equal ("Some message")
you can also capture and inspect an expected exception in one statement, like this:
the [SomeException] thrownBy {
// Code that throws SomeException
} should have message "Some message"