Getting Exception when Safe-Casting to Generic Type in Kotlin












3














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.










share|improve this question



























    3














    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.










    share|improve this question

























      3












      3








      3







      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.










      share|improve this question













      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 21 '18 at 8:07









      Vivek Gupta

      328217




      328217
























          1 Answer
          1






          active

          oldest

          votes


















          2














          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).






          share|improve this answer























          • 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











          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
          });


          }
          });














          draft saved

          draft discarded


















          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









          2














          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).






          share|improve this answer























          • 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
















          2














          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).






          share|improve this answer























          • 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














          2












          2








          2






          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).






          share|improve this answer














          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).







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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. 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
















          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


















          draft saved

          draft discarded




















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          Wiesbaden

          Marschland

          Dieringhausen