Getting Exception when Safe-Casting to Generic Type in Kotlin
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.
java kotlin casting
add a comment |
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.
java kotlin casting
add a comment |
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.
java kotlin casting
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.
java kotlin casting
java kotlin casting
asked Nov 21 '18 at 8:07
Vivek Gupta
328217
328217
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
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).
Type erasure is exactly the reason why this doesn't work. ThecastToContext
function doesn't have any access to the type used at the call site, so it doesn't perform any cast and simply returns the object. That's why the IDE reports an unchecked cast warning in the function.
– yole
Nov 21 '18 at 8:29
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53407633%2fgetting-exception-when-safe-casting-to-generic-type-in-kotlin%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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).
Type erasure is exactly the reason why this doesn't work. ThecastToContext
function doesn't have any access to the type used at the call site, so it doesn't perform any cast and simply returns the object. That's why the IDE reports an unchecked cast warning in the function.
– yole
Nov 21 '18 at 8:29
add a comment |
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).
Type erasure is exactly the reason why this doesn't work. ThecastToContext
function doesn't have any access to the type used at the call site, so it doesn't perform any cast and simply returns the object. That's why the IDE reports an unchecked cast warning in the function.
– yole
Nov 21 '18 at 8:29
add a comment |
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).
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).
edited Nov 21 '18 at 16:54
answered Nov 21 '18 at 8:27
Roland
9,41711141
9,41711141
Type erasure is exactly the reason why this doesn't work. ThecastToContext
function doesn't have any access to the type used at the call site, so it doesn't perform any cast and simply returns the object. That's why the IDE reports an unchecked cast warning in the function.
– yole
Nov 21 '18 at 8:29
add a comment |
Type erasure is exactly the reason why this doesn't work. ThecastToContext
function doesn't have any access to the type used at the call site, so it doesn't perform any cast and simply returns the object. That's why the IDE reports an unchecked cast warning in the function.
– yole
Nov 21 '18 at 8:29
Type erasure is exactly the reason why this doesn't work. The
castToContext
function doesn't have any access to the type used at the call site, so it doesn't perform any cast and simply returns the object. That's why the IDE reports an unchecked cast warning in the function.– yole
Nov 21 '18 at 8:29
Type erasure is exactly the reason why this doesn't work. The
castToContext
function doesn't have any access to the type used at the call site, so it doesn't perform any cast and simply returns the object. That's why the IDE reports an unchecked cast warning in the function.– yole
Nov 21 '18 at 8:29
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53407633%2fgetting-exception-when-safe-casting-to-generic-type-in-kotlin%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown