Mr.Turtle
Mr.Turtle

Reputation: 3090

Exception handling / suppression with higher order function

I have an application in a micro service architecture. This application is getting data from different sources and is getting a lot of different error-responses from the various of other applications. Some exceptions, like 404-Not found exceptions can be thrown and returned to the end-user, but other exceptions (bad requests, ++) can't and need to be suppressed by throwing some other exception.

However, I know this can be solved by try-catching the exceptions and moderating what to throw in that matter, but that would involve a lot of code.. sometimes I want to accept 4-5 different exceptions, while other times only 1-2 exceptions.


Anyhow.. I need some help making a higher order function. I want a function that takes one or more "accepted exceptions" as parameters (they're Runtime-exceptions) and throws only the approved exceptions in a try-catch.

This is what I have tried, but can't seem to get the syntax right (pseudo-code atm.). Any help is really appreciated.

  fun getData() {
    return supressExceptions(
        NotFoundException::class.java, 
        ForbiddenException::class.java, 
        AuthorizationException::class.java) {
      service.getData()
    }
  }

  private inline fun <T, X : RuntimeException> supressExceptions(vararg approvedException: Class<X>, block: () -> T): T =
      try {
        block()
      } catch (ex: Exception) {
        // Loop through the approved exceptions.
        // Throw the approved exception
        throw ex
        // ELSE: do something else if the exception is not approved.
      }

Upvotes: 1

Views: 1152

Answers (3)

Roland
Roland

Reputation: 23352

As already mentioned in the comments: from the naming I would have expected that the suppressExceptions rather accepts a parameter of the exceptions to be suppressed.

I wonder whether you actually rather want to check whether a thrown exception is actually an instance of the given exception types, i.e. if also subclasses of the given types should be approved/suppressed or not.

In such a case I would rather use the following code:

inline fun <T> suppressAllExceptions(vararg exceptExceptions: Class<out Exception> = emptyArray(),
                                     block: () -> T) = try {
  block()
} catch (e: Exception) {
  throw if (exceptExceptions.any { it.isInstance(e) }) {
    e
  } else SuppressedException(e)
}

You would still use it the same way as you have shown:

suppressAllExceptions {
  throw IllegalStateException("i am suppressed soon")
}
suppressAllExceptions(IllegalStateException::class.java, 
                      IllegalArgumentException::class.java) {
  throw IllegalStateException("i am not suppressed")
}
class MyIllegalStateException : IllegalStateException()
suppressAllExceptions(IllegalStateException::class.java, 
                      IllegalArgumentException::class.java) {
  throw MyIllegalStateException("i am not suppressed neither")
} 

The more I think of it: why do you approve different types of exceptions at different places? This doesn't sound right to me. You probably rather want to suppress all exceptions except some well-defined ones and in such a case you do not need such a generic function in the first place, but rather have one suppressing function that contains that well-defined list:

/**
 * Suppresses all exceptions except the well-defined ones: [NotFoundException], ...
 */
inline fun <T> suppressExceptions(block: () -> T) = try {
  block()
} catch (e: Exception) {
  throw when (e) {
    is NotFoundException,
    is ForbiddenException,
    // all the other well-defined non-suppressable types
    is AuthorizationException -> e
    else -> SuppressedException(e)
  }
}

Upvotes: 1

Mr.Turtle
Mr.Turtle

Reputation: 3090

This can be achieved by any:

  private inline fun <T, X : RuntimeException> supressExceptions(vararg approvedException: Class<X>,
      block: () -> T): T =
      try {
        block()
      } catch (ex: Exception) {
        when {
          approvedException.any { ex::class.java == it } -> throw ex
          else -> {
            throw SupressedException(ex)
          }
        }
      }

any: Returns true if at least one entry matches the given predicate.

Upvotes: 1

Yoni Gibbs
Yoni Gibbs

Reputation: 7056

Is the below what you're looking for?

private inline fun <T> supressExceptions(vararg approvedException: Class<out RuntimeException>, block: () -> T): T =
        try {
            block()
        } catch (ex: Exception) {
            if (approvedException.contains(ex::class.java)) {
                // Approved exception
                throw ex
            }
            // ELSE: do something else if the exception is not approved.
            else throw Exception("Something else")
        }

Upvotes: 2

Related Questions