Reputation: 2814
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 the data is not of the type TypeA
.
castDirectly()
-> this returns null
when the cast is not possible.
Please suggest how can this be done.
Upvotes: 5
Views: 1808
Reputation: 23352
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 wherever 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).
Upvotes: 4