Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a reusable transform for String to Enum value across a group of Enum classes? (Kotlin)

Tags:

enums

kotlin

I have a group >5 of Enum classes that take String parameter in its values, and I want to have simple code for all these Enum classes to convert from a String field in JSON object.

enum class Religiousness(val jsonStr: String, val resID: Int) {
    NotAtAll("none", R.string.not_religious),
    Somewhat("somewhat", R.string.somewhat_religious),
    Very("very", R.string.very_religious),
    ;
    override fun toString() = jsonStr
    fun displayString(res: Resources) = res.getString(resID)
}

I want to be able to write code like this

fun JsonConvertStrToEnum(enumClass: Class<Enum<*>>, str: String): Enum<*> {
    for (enumval in enumClass.enumConstants) {
        if ((enumval as IJsonStringConvertible).jsonStr() == str)
            return enumval
    }
    throw IllegalArgumentException("Gave an invalid enum value for class ${enumClass.canonicalName}")
}

I am having a hard time figuring out if IJsonStringConvertible can work, and what its definition would be, and how to implement it in the Enum value instances. Any advice?

Update: I have now written the converter as this. Is this the best way? Can I also express that the return value is a subtype of the parameter so don't need to cast return value?

fun JsonConvertStrToEnum(enumClass: Class<out Enum<*>>, str: String): Enum<*> {
    for (enumval in enumClass.enumConstants) {
        if (enumval.toString() == str)
            return enumval
    }
    throw IllegalArgumentException("Gave an invalid enum value for class ${enumClass.canonicalName}")
}
like image 354
androidguy Avatar asked Dec 20 '25 14:12

androidguy


1 Answers

Enums as other classes can implement interfaces like so:

interface IJsonStringConvertible {
    val jsonStr:String
}

enum class Religiousness(override val jsonStr: String, val resID: Int) : IJsonStringConvertible {
    NotAtAll("none", R.string.not_religious),
    Somewhat("somewhat", R.string.somewhat_religious),
    Very("very", R.string.very_religious),
    ;

    override fun toString() = jsonStr
    fun displayString(res: Resources) = res.getString(resID)
}

Which would then be used as:

for (enumval in enumClass.enumConstants) {
    if ((enumval as IJsonStringConvertible).jsonStr == str)
        return enumval
}

However the above lookup can be expensive (if used millions of times). Take a look at the reverse lookup question to find out how to do it more efficiently.

like image 132
miensol Avatar answered Dec 24 '25 12:12

miensol



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!