Enum.valueOf in Kotlin
Solution 1
Your function works if you specify the type parameter value explicitly:
val value = safeValueOf<TestEnum>("test")
The original code is supposed to work as well, but doesn't work because of a bug in the type inference implementation: https://youtrack.jetbrains.com/issue/KT-11218
Solution 2
Crash-safe Solution
Create an extension and then call valueOf<MyEnum>("value")
. If the type is invalid, you'll get null and have to handle it
inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: IllegalArgumentException) {
null
}
}
Alternatively, you can set a default value, calling valueOf<MyEnum>("value", MyEnum.FALLBACK)
, and avoiding a null response. You can extend your specific enum to have the default be automatic
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: IllegalArgumentException) {
default
}
}
Or if you want both, make the second:
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Solution 3
I would typically add something like this to enum:
companion object {
fun from(type: String?): TestEnum = values().find { it.name == type } ?: DEFAULT
}
this would make a clean call
val value = TestEnum.from("test")
of course you can make it return null
Solution 4
Since Kotlin 1.1, it's possible to access the constants in an enum class in a generic way, using the enumValues() and enumValueOf() functions:
enum class RGB { RED, GREEN, BLUE }
inline fun <reified T : Enum<T>> printAllValues() {
print(enumValues<T>().joinToString { it.name })
}
printAllValues<RGB>() // prints RED, GREEN, BLUE
https://kotlinlang.org/docs/reference/enum-classes.html#working-with-enum-constants
Related videos on Youtube
AndroidEx
Interested in different aspects of the mobile development
Updated on August 18, 2020Comments
-
AndroidEx over 3 years
Is there a way to make something like this work in Kotlin without the reflection?
inline fun <reified T : kotlin.Enum<T>> safeValueOf(type: String?): T? { return java.lang.Enum.valueOf(T::class.java, type) }
The example below doesn't compile due to:
Type parameter bound for T in
inline fun <reified T : kotlin.Enum<T>> safeValueOf(type: kotlin.String?): T?
is not satisfied: inferred typeTestEnum?
is not a subtype ofkotlin.Enum<TestEnum?>
enum class TestEnum fun main() { val value: TestEnum? = safeValueOf("test") }
-
yole about 8 yearsYour function works if you specify the type parameter value explicitly:
val value = safeValueOf<TestEnum>("test")
-
awesoon about 8 yearsWhy not just use Kotlin implementation of
valueOf
? -
AndroidEx about 8 years@yole thanks, that's it. Do you mind posting this as the answer?
-
AndroidEx about 8 years@soon I would like to extend the functionality of
valueOf
and use it with different enum types -
charlie_pl about 7 yearsCan I ask how this is safeValueOf? this can still throw exceptions
-
AndroidEx about 7 years@charlie_pl the question title doesn't really say anything about safety. The problem at that time was making this construct work, and, as you've correctly noted, the
safeValueOf
is not safe here as it's just a minimal example of the issue at hand. But you can easily imagine how it can be made safe from here.
-