Home > Mobile >  ClassCastException in Kotlin even though the conditional statement checks that it's of right ty
ClassCastException in Kotlin even though the conditional statement checks that it's of right ty

Time:11-10

I'm burning cycles trying to understand why I'm getting a cast error when I know for a fact that it's a string.

Anyone else seen this in Kotlin? (it fails at the second to last line).

val stringValue =
    if (attributesMap[it] !is String) { // same as !(obj is String)
        gson.toJson(attributesMap[it])
    } else if (attributesMap[it] == null) {
        ""
    } else {
        if (attributesMap[it] is String)
            logger.info("it's a string wth...${attributesMap[it]}")
            
        attributesMap[it] // <--- The stacktrace shows this line as the culprit, and the above "it's a string line" is printed out as well
    }

Here's the error:

java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.lang.String (java.util.ArrayList and java.lang.String are in module java.base of loader 'bootstrap')

CodePudding user response:

That is why it is always good idea to put { } in if conditions. Given that you have no { }, the condition if (attributesMap[it] is String) only applies to a single line below. I think you wanted to write the following:

val stringValue =
    if (attributesMap[it] !is String) { // same as !(obj is String)
        gson.toJson(attributesMap[it])
    } else if (attributesMap[it] == null) {
        ""
    } else {
        if (attributesMap[it] is String) {
            logger.info("it's a string wth...${attributesMap[it]}")
            attributesMap[it] // <--- The stacktrace shows this line as the culprit, and the above "it's a string line" is printed out as well
        }
    }

Or maybe:

val stringValue =
    if (attributesMap[it] !is String) { // same as !(obj is String)
        gson.toJson(attributesMap[it])
    } else if (attributesMap[it] == null) {
        ""
    } else if (attributesMap[it] is String) {
        logger.info("it's a string wth...${attributesMap[it]}")
        attributesMap[it] // <--- The stacktrace shows this line as the culprit, and the above "it's a string line" is printed out as well
    } else {
        // something else
    }

CodePudding user response:

As @João Dias mentioned in his answer, the problem is the way you have written this if statement.

if (attributesMap[it] is String)
    logger.info("it's a string wth...${attributesMap[it]}")
            
attributesMap[it] // <--- The stacktrace shows this line as the culprit, and the above "it's a string line" is printed out as well
attributesMap[it] // <--- The stacktrace shows this line as the culprit, and 

is falling outside of the if statement, so the right way is to put this inside a curly bracket like

if (attributesMap[it] is String) {
    logger.info("it's a string wth...${attributesMap[it]}")
            
    attributesMap[it] // <--- The stacktrace shows this line as the culprit, and the above "it's a string line" is printed out as well
} else {
   //
}

CodePudding user response:

I guess the problem is that attributesMap[it] is not a property itself. It's actually a function call attributesMap.get(it). That's why compiler is not able to smart cast it.

Also, I am not sure of your order of if statements. If attributesMap[it] !is String is false, attributesMap[it] == null will definitely be false.

Try this code, see if it works for you.

val value = attributes[it] // Store the value beforehand
val stringValue =
    if(value == null)
        ""
    else if(value is String)
        value
    else
        gson.toJson(value)

You can also replace this if-else ladder with a when statement.

Playground

  • Related