Skip to content

Instantly share code, notes, and snippets.

@hrules6872
Last active September 22, 2022 16:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrules6872/f2664a6320ce4a3fb368524ab34ad5c8 to your computer and use it in GitHub Desktop.
Save hrules6872/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)
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")
}
}
}
}
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