Getting Exception when Safe-Casting to Generic Type in Kotlin

Vivek Gupta :

I am using safe casting option in kotlin i.e. as? still i am getting class cast exception when the data types are not compatible, this is happening when i am doing this via a generic method written to perform case, however if i directly perform the cast it returns null as expected from a safe cast

class CastTest(val data: Any) {

   fun castViaGenericMethod(): TypeA? {
      return castToContext<TypeA>()
   }

   fun castDirectly(): TypeA? {
      return data as? TypeA
   }

   private fun <CONTEXT> castToContext(): CONTEXT? = data as? CONTEXT

}

castViaGenericMethod() -> this method throws ClassCastException when data is not TypeA type. castDirectly() -> this returns null when the cast is not possible.

Please suggest how can this be done.

Roland :

To fix your problem you could use a reified type:

inline fun <reified CONTEXT> castToContext() = data as? CONTEXT

The reason, why it didn't work as you expect, is, that generic types are erased at runtime.

If we look at the byte code, we see that everywhere, where your CONTEXT-generic type is written, it becomes java/lang/Object:

private final castToContext()Ljava/lang/Object;
 L0
  LINENUMBER 12 L0
    ALOAD 0
    GETFIELD CastTest.data : Ljava/lang/Object;
    DUP
    INSTANCEOF java/lang/Object // (1)
    IFNE L1                     // (1)
    POP          // (2)
    ACONST_NULL  // (2)
   L1
    ARETURN
   L2
    LOCALVARIABLE this LCastTest; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

So the safe cast actually makes a check whether the given object is not of type java/lang/Object (1) and sets the value to be returned to null if that's the case. But as it is of type java/lang/Object, the value is just returned as is. On the calling side however the byte code looks as follows:

LINENUMBER 4 L0
ALOAD 0
INVOKESPECIAL CastTest.castToContext ()Ljava/lang/Object; // the call
CHECKCAST TypeA // the type check
ARETURN

It does an additional CHECKCAST TypeA after calling castToContext and there you get your ClassCastException as the value was not nullified (generic type information was erased at runtime).

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=102291&siteId=1