Last active
September 22, 2022 16:01
-
-
Save hector6872/f2664a6320ce4a3fb368524ab34ad5c8 to your computer and use it in GitHub Desktop.
safeOf(): returns the first subclass of a Sealed Class matching the given [predicate], or [default] if no such element was found / values(): list all subclasses (Kotlin)
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
fun <T : Any> KClass<T>.safeOf(default: T, predicate: (T) -> Boolean): T = this.values().find { predicate(it) } ?: default | |
fun <T : Any> KClass<T>.values(): List<T> { | |
if (!this.isSealed) throw IllegalCallerException("Receiver MUST be a Sealed class") | |
return this.sealedSubclasses.map { sealedSubclass -> | |
when { | |
sealedSubclass.objectInstance != null -> sealedSubclass.objectInstance!! | |
else -> try { | |
sealedSubclass.primaryConstructor?.callBy(mapOf()) ?: throw Exception() | |
} catch (ignored: Exception) { | |
throw ReflectiveOperationException("(data) classes MUST have a primary constructor and default parameters") | |
} | |
} | |
} | |
} |
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 SealedClassExtTest { | |
@Test fun `given an Object id, should return an Object`() { | |
assertThat(Sealed.safeOf(SealedObjectChild.id)).isInstanceOf(SealedObjectChild::class.java) | |
} | |
@Test fun `given a Class id, then return a Class`() { | |
assertThat(Sealed.safeOf(SealedClassChild().id)).isInstanceOf(SealedClassChild::class.java) | |
} | |
@Test fun `given an unknown id, then return Default`() { | |
assertThat(Sealed.safeOf(Int.MAX_VALUE)).isInstanceOf(DEFAULT::class.java) | |
} | |
@Test fun `when using a not Sealed class, then throw an Exception`() { | |
assertThatThrownBy { | |
assertThat(NotSealed.safeOf(NotSealedDefaultChild.id)).isInstanceOf(NotSealedDefaultChild::class.java) | |
}.isInstanceOf(IllegalCallerException::class.java) | |
} | |
@Test fun `given a Class without default parameters id, then throw an Exception`() { | |
assertThatThrownBy { | |
assertThat(WithoutDefaultParametersSealed.safeOf(WithoutDefaultParametersSealedChild(param1 = 0).id)).isInstanceOf(DEFAULT::class.java) | |
}.isInstanceOf(ReflectiveOperationException::class.java) | |
} | |
} | |
private open class NotSealed(val id: Int) { | |
companion object { | |
val DEFAULT = NotSealedDefaultChild | |
fun safeOf(id: Int?): NotSealed = NotSealed::class.safeOf(DEFAULT) { (it as? NotSealed)?.id == id } | |
} | |
object NotSealedDefaultChild : NotSealed(id = 0) | |
} | |
private sealed class Sealed(val id: Int, open val param1: Int) { | |
companion object { | |
val DEFAULT = SealedDefaultChild | |
fun safeOf(id: Int?): Sealed = Sealed::class.safeOf(DEFAULT) { (it as? Sealed)?.id == id } | |
} | |
object SealedDefaultChild : Sealed(id = 0, param1 = 0) | |
object SealedObjectChild : Sealed(id = 1, param1 = 0) | |
class SealedClassChild(override val param1: Int = 0) : Sealed(id = 3, param1 = param1) | |
} | |
private sealed class WithoutDefaultParametersSealed(val id: Int, open val param1: Int) { | |
companion object { | |
val DEFAULT = WithoutDefaultParametersSealedChild(0) | |
fun safeOf(id: Int?): WithoutDefaultParametersSealed = WithoutDefaultParametersSealed::class.safeOf(DEFAULT) { (it as? WithoutDefaultParametersSealed)?.id == id } | |
} | |
class WithoutDefaultParametersSealedChild(override val param1: Int) : WithoutDefaultParametersSealed(id = 0, param1 = param1) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment