So I’m trying to write a method that catches a specified type of exception and throws a specified type of exception.
I have this:
inline fun <reified FromException : Exception, ToException : Exception, Returns : Any> mapException(
fromException: KClass<FromException>,
toException: KClass<ToException>,
block: () -> Returns
): Returns {
try{
Throwable::class
return block()
} catch(e: Exception) {
if (e is FromException) {
throw FromException(e.message, e)
} else {
throw e
}
}
}
But I’m getting the error “Type parameter FromException cannot be called as function”. Is there a way I can do this that doesn’t involve reflection or do I have to use reflection?
The problem is that you don’t know what constructor(s) FromException has. It’s certainly conventional (and good practice) for an exception to have constructor(s) taking a message string and/or a wrapped exception — but there’s nothing to enforce that, and so the compiler can’t guarantee that there’s one to call. (Also, even if it could, you couldn’t use that syntax.)
As an alternative, how about taking a parameter which is a lambda of type () -> FromException? The function could call that if needed to generate the exception, and it might be more likely to infer the exception type.
(By the way, should the test be negated, i.e. !is FromException? If not, what’s the benefit in wrapping one FromException in another?)
Can you expand a bit on what you’re trying to accomplish? To start with, the ToException type is never used. I’m also not exactly clear on what your code is attempting to accomplish. Is it meant to be something like “if the thrown exception is FromException, create and throw ToException constructed from FromException”? Assuming it is something like that, you could probably write it like this:
inline fun <reified FromException : Exception, ToException : Exception, Returns : Any> mapException(
exceptionConvertor: (FromException) -> ToException,
block: () -> Returns
): Returns {
try {
return block()
} catch(e: Exception) {
if (e is FromException) {
throw exceptionConvertor(e)
} else {
throw e
}
}
}
But honestly, I don’t know how much value you’d get out of such a function… it doesn’t seem like you’re saving much repetition, when you could simply put try catch blocks in the place where you would call this function, and only catch the type of exception you care about.
If you specifically want to convert an exception instead, an easier way to do it might be with an extension function.
inline fun <reified From : Exception, reified To : Exception> Exception.convertIfIsType(convertor: (From) -> To): Exception = if (this is From)
convertor(this)
else
this
Then you could use it in your code like so:
try {
codeThatThrowsExceptions()
} catch (e: Exception) {
throw e.convertIfIsType<MyCustomException, MyOtherException> {
MyOtherException(it) // assuming MyOtherException has a constructor signature that accepts an instance of MyCustomException
}
}