Enum.valueOf in Kotlin

28,619

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

Share:
28,619

Related videos on Youtube

AndroidEx
Author by

AndroidEx

Interested in different aspects of the mobile development

Updated on August 18, 2020

Comments

  • AndroidEx
    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 type TestEnum? is not a subtype of kotlin.Enum<TestEnum?>

    enum class TestEnum
    
    fun main() {
        val value: TestEnum? = safeValueOf("test")
    }
    
    • yole
      yole about 8 years
      Your function works if you specify the type parameter value explicitly: val value = safeValueOf<TestEnum>("test")
    • awesoon
      awesoon about 8 years
      Why not just use Kotlin implementation of valueOf?
    • AndroidEx
      AndroidEx about 8 years
      @yole thanks, that's it. Do you mind posting this as the answer?
    • AndroidEx
      AndroidEx about 8 years
      @soon I would like to extend the functionality of valueOf and use it with different enum types
    • charlie_pl
      charlie_pl about 7 years
      Can I ask how this is safeValueOf? this can still throw exceptions
    • AndroidEx
      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.