Created
February 1, 2022 09:08
-
-
Save rommansabbir/1923a10eb1896bf8c05f4776a1f1a81a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SafeExecutorExample { | |
companion object { | |
@JvmStatic | |
fun main(args: Array<String>) { | |
withSafeExecutor<Any> { | |
Either.Right(Any()) } | |
/* | |
Test by throwing exception. | |
*/ | |
withSafeExecutor<Any> { throw Exception("Test") }.either( | |
{ println(it) /* java.lang.Exception: Test */ }, | |
{ println(it) /* Not Invoked */ } | |
) | |
withSafeExecutor<String> { | |
println("Doing some work here before returning result.") | |
return@withSafeExecutor Either.Right("Correct Result.") | |
}.either( | |
{ println(it) /* Not Invoked */ }, | |
{ println(it) /* Correct Result. */} | |
) | |
} | |
} | |
} | |
/** | |
* Extension function to execute instruction through [SafeExecutor] | |
*/ | |
fun <T> withSafeExecutor(callback: () -> Either<Exception, T>): Either<Exception, T> { | |
return SafeExecutor.getInstance().execute(callback) | |
} | |
/** | |
* Suspended extension function to execute instruction through [SafeExecutor] | |
*/ | |
suspend fun <T> withSafeExecutorCoroutine(callback: () -> Either<Exception, T>): Either<Exception, T> { | |
return SafeExecutor.getInstance().executeCoroutine(callback) | |
} | |
/** | |
* [SafeExecutor] which enable to execute business logic without | |
* explicitly defining or worrying about managing [Exception]. | |
* Also, support [suspend] functions too. | |
*/ | |
interface SafeExecutor { | |
/** | |
* Execute the given instruction. | |
* | |
* @param callback callback to invoke the given instruction. | |
* | |
* @return [Either<Exception, T>] | |
*/ | |
fun <T> execute(callback: () -> Either<Exception, T>): Either<Exception, T> | |
/** | |
* Execute the given instruction under a respective coroutine scope. | |
* | |
* @param callback callback to invoke the given instruction. | |
* | |
* @return [Either<Exception, T>] | |
*/ | |
suspend fun <T> executeCoroutine(callback: () -> Either<Exception, T>): Either<Exception, T> | |
companion object { | |
private val instance by lazy { SafeExecutorImpl() } | |
/* | |
Return the SafeExecutor instance. | |
*/ | |
fun getInstance(): SafeExecutor = instance | |
} | |
} | |
class SafeExecutorImpl : SafeExecutor { | |
override fun <T> execute(callback: () -> Either<Exception, T>): Either<Exception, T> { | |
return try { | |
callback.invoke() | |
} catch (e: Exception) { | |
Either.Left(e) | |
} catch (e: RuntimeException) { | |
Either.Left(e) | |
} | |
} | |
override suspend fun <T> executeCoroutine(callback: () -> Either<Exception, T>): Either<Exception, T> { | |
return try { | |
callback.invoke() | |
} catch (e: Exception) { | |
Either.Left(e) | |
} catch (e: RuntimeException) { | |
Either.Left(e) | |
} | |
} | |
} | |
sealed class Either<out L, out R> { | |
/** * Represents the left side of [Either] class which by convention is a "Failure". */ | |
data class Left<out L>(val a: L) : Either<L, Nothing>() | |
/** * Represents the right side of [Either] class which by convention is a "Success". */ | |
data class Right<out R>(val b: R) : Either<Nothing, R>() | |
val isRight get() = this is Right<R> | |
val isLeft get() = this is Left<L> | |
fun <L> left(a: L) = Left(a) | |
fun <R> right(b: R) = Right(b) | |
fun either(fnL: (L) -> Any, fnR: (R) -> Any): Any = when (this) { | |
is Left -> fnL(a) | |
is Right -> fnR(b) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment