innov8
innov8

Reputation: 2219

Kotlin enum generic function

I need a Kotlin function to return an enum value from a string when given a default value for the enum.

Each enum class has a valueOf() method, but I am after a generic that works for any given enum class.

For a sample enum I can do:

enum class Example {
    first,
    second,
    third ;

    companion object {  // Note same exact code also works if not in companion object
        fun valueOrDefault(value: String, default: Example) = try {
            valueOf(value)
        } catch (e: IllegalStateException) {
            default
        }
    }
}

The challenge is how to make a generic. I have code that needs to do this for any given enum class.

The problem is I cannot see how to write a generic version of the function.

So far I have:

fun <T: Enum<Any>>valueOrDefault(value: String, default: T): T = try {
     valueOf(value) as T
} catch (e: IllegalStateException) {
    default
}

But no matter what combination I use can cannot get access to the valueOf() method. I tried making the function and extension function for T , but that did not help. It could be that the syntax of Enum<Any> is incorrect... but any insight appreciated.

Upvotes: 0

Views: 2041

Answers (1)

hotkey
hotkey

Reputation: 147961

You can use an intrinsic function that Kotlin provides for getting a value of an arbitrary enum class by name: enumValueOf<T>(name: String).

As it needs to get the type information at compile time from each of the call sites in order to find the corresponding enum class, it can only be applied to reified type parameters in inline functions, so you will have to add those modifiers to your function.

If it fails, it will throw an IllegalArgumentException (on the JVM) or IllegalStateException (with Kotlin/JS as of now), so to return the default value, you have to catch the exception.

The resulting code would be:

inline fun <reified T: Enum<T>> valueOrDefault(value: String, default: T): T = try {
    enumValueOf(value)
} catch (e: IllegalArgumentException) {
    default
} catch (e: IllegalStateException) {
    default 
}

(runnable demo)

The T: Enum<T> type parameter is how an enum classes are restricted: they all implement the Enum interface providing the self type as the type argument.

There's another intrinsic function that gets all enum values from a reified type parameter representing an enum class: enumValues

Another way that doesn't require reified type parameters but can only work with Kotlin/JVM but not other platforms is to get the default's javaClass.enumConstants and find the value by name.

Upvotes: 3

Related Questions