ClassLoader in Java












1














I was playing with classloaders in java and found the following behavior. I could logically reason out about this, but I'm not sure what I'm assuming is completely true. I'd like to know more formal explanation of this behavior.



What I was trying?
So I had the following code:



URL classURLs = {new URL("file://C:/Users/HP/IdeaProjects/test/out/production/test/")};
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, null);
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");

// the following line will give a ClassCastException
Person p = (Person) personClass.getDeclaredConstructor().newInstance();


Now the last line gives me a ClassCastException.



My reasoning (guess) about why I'm getting a ClassCastException: The classloader of personClass is urlClassLoader whereas the classloader of Person class is actually application class loader or system class loader (please correct me if I'm wrong). These class loaders don't match and I'm getting a ClassCastException. (I'm here assuming that when typecasting a check is performed on the classloaders)



So now I continue exploring and alter the construction of URLClassLoader in the following way:



URLClassLoader urlClassLoader = new URLClassLoader(classURLs, Main.class.getClassLoader());


Here Main is the enclosing class. The above line saves me from a ClassCastException.



My reasoning (guess) about this: As now the urlClassLoader has application class loader as its parent (this application class loader is same that is used to load Person class), while trying to cast, Java check if the classloaders match and this check continues with the parent of the urlClassLoader, after going one step up the classloaders match and there is no ClassCastException.



I assume that the classloader of the class of the object to be typecasted is checked against the classloader of the class into which you need to typecast and if this don't match the parent of the classloader of the class of object is tried for the match and this continues.



Please correct me if I'm wrong at any point and also provide pointers to the formal documentation of this behavior.



I have seen this link, but this don't provide the details I've asked.










share|improve this question






















  • Possible duplicate of cast across classloader?
    – MTCoster
    Nov 19 '18 at 17:59










  • Read this For JVM same class but loaded with the different class loaders - are two different types. It have advantages like - using two different version of the same library in the same program, and solve the JAR hell. OSGI frameworks using this feature, as well as Java 9+ modules.
    – Victor Gubin
    Nov 19 '18 at 18:02












  • @MTCoster: I've seen this. But this don't explain whether what I'm thinking is correct or not. Specifically about the hierarchy comparison of classloaders
    – Lavish Kothari
    Nov 19 '18 at 18:09






  • 2




    Person p = (Person) ... will use the Person version loaded by the application classloader at application start. By nulling out the classloader on the URLClassLoader you basically prevent urlClassloader from looking up the person class already loaded and force it to load its own version. On returning the newly created instance, let's say objPerson#UrlCL, a cast to objPerson#AppCL is forced which fails as notably the object was loaded by a different CL. Basically A#CL1 != A#CL2 applies here
    – Roman Vottner
    Nov 19 '18 at 18:30
















1














I was playing with classloaders in java and found the following behavior. I could logically reason out about this, but I'm not sure what I'm assuming is completely true. I'd like to know more formal explanation of this behavior.



What I was trying?
So I had the following code:



URL classURLs = {new URL("file://C:/Users/HP/IdeaProjects/test/out/production/test/")};
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, null);
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");

// the following line will give a ClassCastException
Person p = (Person) personClass.getDeclaredConstructor().newInstance();


Now the last line gives me a ClassCastException.



My reasoning (guess) about why I'm getting a ClassCastException: The classloader of personClass is urlClassLoader whereas the classloader of Person class is actually application class loader or system class loader (please correct me if I'm wrong). These class loaders don't match and I'm getting a ClassCastException. (I'm here assuming that when typecasting a check is performed on the classloaders)



So now I continue exploring and alter the construction of URLClassLoader in the following way:



URLClassLoader urlClassLoader = new URLClassLoader(classURLs, Main.class.getClassLoader());


Here Main is the enclosing class. The above line saves me from a ClassCastException.



My reasoning (guess) about this: As now the urlClassLoader has application class loader as its parent (this application class loader is same that is used to load Person class), while trying to cast, Java check if the classloaders match and this check continues with the parent of the urlClassLoader, after going one step up the classloaders match and there is no ClassCastException.



I assume that the classloader of the class of the object to be typecasted is checked against the classloader of the class into which you need to typecast and if this don't match the parent of the classloader of the class of object is tried for the match and this continues.



Please correct me if I'm wrong at any point and also provide pointers to the formal documentation of this behavior.



I have seen this link, but this don't provide the details I've asked.










share|improve this question






















  • Possible duplicate of cast across classloader?
    – MTCoster
    Nov 19 '18 at 17:59










  • Read this For JVM same class but loaded with the different class loaders - are two different types. It have advantages like - using two different version of the same library in the same program, and solve the JAR hell. OSGI frameworks using this feature, as well as Java 9+ modules.
    – Victor Gubin
    Nov 19 '18 at 18:02












  • @MTCoster: I've seen this. But this don't explain whether what I'm thinking is correct or not. Specifically about the hierarchy comparison of classloaders
    – Lavish Kothari
    Nov 19 '18 at 18:09






  • 2




    Person p = (Person) ... will use the Person version loaded by the application classloader at application start. By nulling out the classloader on the URLClassLoader you basically prevent urlClassloader from looking up the person class already loaded and force it to load its own version. On returning the newly created instance, let's say objPerson#UrlCL, a cast to objPerson#AppCL is forced which fails as notably the object was loaded by a different CL. Basically A#CL1 != A#CL2 applies here
    – Roman Vottner
    Nov 19 '18 at 18:30














1












1








1







I was playing with classloaders in java and found the following behavior. I could logically reason out about this, but I'm not sure what I'm assuming is completely true. I'd like to know more formal explanation of this behavior.



What I was trying?
So I had the following code:



URL classURLs = {new URL("file://C:/Users/HP/IdeaProjects/test/out/production/test/")};
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, null);
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");

// the following line will give a ClassCastException
Person p = (Person) personClass.getDeclaredConstructor().newInstance();


Now the last line gives me a ClassCastException.



My reasoning (guess) about why I'm getting a ClassCastException: The classloader of personClass is urlClassLoader whereas the classloader of Person class is actually application class loader or system class loader (please correct me if I'm wrong). These class loaders don't match and I'm getting a ClassCastException. (I'm here assuming that when typecasting a check is performed on the classloaders)



So now I continue exploring and alter the construction of URLClassLoader in the following way:



URLClassLoader urlClassLoader = new URLClassLoader(classURLs, Main.class.getClassLoader());


Here Main is the enclosing class. The above line saves me from a ClassCastException.



My reasoning (guess) about this: As now the urlClassLoader has application class loader as its parent (this application class loader is same that is used to load Person class), while trying to cast, Java check if the classloaders match and this check continues with the parent of the urlClassLoader, after going one step up the classloaders match and there is no ClassCastException.



I assume that the classloader of the class of the object to be typecasted is checked against the classloader of the class into which you need to typecast and if this don't match the parent of the classloader of the class of object is tried for the match and this continues.



Please correct me if I'm wrong at any point and also provide pointers to the formal documentation of this behavior.



I have seen this link, but this don't provide the details I've asked.










share|improve this question













I was playing with classloaders in java and found the following behavior. I could logically reason out about this, but I'm not sure what I'm assuming is completely true. I'd like to know more formal explanation of this behavior.



What I was trying?
So I had the following code:



URL classURLs = {new URL("file://C:/Users/HP/IdeaProjects/test/out/production/test/")};
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, null);
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");

// the following line will give a ClassCastException
Person p = (Person) personClass.getDeclaredConstructor().newInstance();


Now the last line gives me a ClassCastException.



My reasoning (guess) about why I'm getting a ClassCastException: The classloader of personClass is urlClassLoader whereas the classloader of Person class is actually application class loader or system class loader (please correct me if I'm wrong). These class loaders don't match and I'm getting a ClassCastException. (I'm here assuming that when typecasting a check is performed on the classloaders)



So now I continue exploring and alter the construction of URLClassLoader in the following way:



URLClassLoader urlClassLoader = new URLClassLoader(classURLs, Main.class.getClassLoader());


Here Main is the enclosing class. The above line saves me from a ClassCastException.



My reasoning (guess) about this: As now the urlClassLoader has application class loader as its parent (this application class loader is same that is used to load Person class), while trying to cast, Java check if the classloaders match and this check continues with the parent of the urlClassLoader, after going one step up the classloaders match and there is no ClassCastException.



I assume that the classloader of the class of the object to be typecasted is checked against the classloader of the class into which you need to typecast and if this don't match the parent of the classloader of the class of object is tried for the match and this continues.



Please correct me if I'm wrong at any point and also provide pointers to the formal documentation of this behavior.



I have seen this link, but this don't provide the details I've asked.







java classloader urlclassloader






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 19 '18 at 17:52









Lavish KothariLavish Kothari

736412




736412












  • Possible duplicate of cast across classloader?
    – MTCoster
    Nov 19 '18 at 17:59










  • Read this For JVM same class but loaded with the different class loaders - are two different types. It have advantages like - using two different version of the same library in the same program, and solve the JAR hell. OSGI frameworks using this feature, as well as Java 9+ modules.
    – Victor Gubin
    Nov 19 '18 at 18:02












  • @MTCoster: I've seen this. But this don't explain whether what I'm thinking is correct or not. Specifically about the hierarchy comparison of classloaders
    – Lavish Kothari
    Nov 19 '18 at 18:09






  • 2




    Person p = (Person) ... will use the Person version loaded by the application classloader at application start. By nulling out the classloader on the URLClassLoader you basically prevent urlClassloader from looking up the person class already loaded and force it to load its own version. On returning the newly created instance, let's say objPerson#UrlCL, a cast to objPerson#AppCL is forced which fails as notably the object was loaded by a different CL. Basically A#CL1 != A#CL2 applies here
    – Roman Vottner
    Nov 19 '18 at 18:30


















  • Possible duplicate of cast across classloader?
    – MTCoster
    Nov 19 '18 at 17:59










  • Read this For JVM same class but loaded with the different class loaders - are two different types. It have advantages like - using two different version of the same library in the same program, and solve the JAR hell. OSGI frameworks using this feature, as well as Java 9+ modules.
    – Victor Gubin
    Nov 19 '18 at 18:02












  • @MTCoster: I've seen this. But this don't explain whether what I'm thinking is correct or not. Specifically about the hierarchy comparison of classloaders
    – Lavish Kothari
    Nov 19 '18 at 18:09






  • 2




    Person p = (Person) ... will use the Person version loaded by the application classloader at application start. By nulling out the classloader on the URLClassLoader you basically prevent urlClassloader from looking up the person class already loaded and force it to load its own version. On returning the newly created instance, let's say objPerson#UrlCL, a cast to objPerson#AppCL is forced which fails as notably the object was loaded by a different CL. Basically A#CL1 != A#CL2 applies here
    – Roman Vottner
    Nov 19 '18 at 18:30
















Possible duplicate of cast across classloader?
– MTCoster
Nov 19 '18 at 17:59




Possible duplicate of cast across classloader?
– MTCoster
Nov 19 '18 at 17:59












Read this For JVM same class but loaded with the different class loaders - are two different types. It have advantages like - using two different version of the same library in the same program, and solve the JAR hell. OSGI frameworks using this feature, as well as Java 9+ modules.
– Victor Gubin
Nov 19 '18 at 18:02






Read this For JVM same class but loaded with the different class loaders - are two different types. It have advantages like - using two different version of the same library in the same program, and solve the JAR hell. OSGI frameworks using this feature, as well as Java 9+ modules.
– Victor Gubin
Nov 19 '18 at 18:02














@MTCoster: I've seen this. But this don't explain whether what I'm thinking is correct or not. Specifically about the hierarchy comparison of classloaders
– Lavish Kothari
Nov 19 '18 at 18:09




@MTCoster: I've seen this. But this don't explain whether what I'm thinking is correct or not. Specifically about the hierarchy comparison of classloaders
– Lavish Kothari
Nov 19 '18 at 18:09




2




2




Person p = (Person) ... will use the Person version loaded by the application classloader at application start. By nulling out the classloader on the URLClassLoader you basically prevent urlClassloader from looking up the person class already loaded and force it to load its own version. On returning the newly created instance, let's say objPerson#UrlCL, a cast to objPerson#AppCL is forced which fails as notably the object was loaded by a different CL. Basically A#CL1 != A#CL2 applies here
– Roman Vottner
Nov 19 '18 at 18:30




Person p = (Person) ... will use the Person version loaded by the application classloader at application start. By nulling out the classloader on the URLClassLoader you basically prevent urlClassloader from looking up the person class already loaded and force it to load its own version. On returning the newly created instance, let's say objPerson#UrlCL, a cast to objPerson#AppCL is forced which fails as notably the object was loaded by a different CL. Basically A#CL1 != A#CL2 applies here
– Roman Vottner
Nov 19 '18 at 18:30












2 Answers
2






active

oldest

votes


















1














The formal documentation for the behaviour that you observe is in the ClassLoader#loadClass() documentation:




Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:




  1. Invoke findLoadedClass(String) to check if the class has already been loaded.


  2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.


  3. Invoke the findClass(String) method to find the class.





If you specify a parent class loader your URLClassLoader checks the parent class loader for the class before trying to load the class itself, which means that it will find the class from your application class path.



So if you set the parent class loader, this line:



Class<?> personClass = urlClassLoader.loadClass("com.test.Person");


behaves the same as



Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");


if the class com.test.Person is available on the application class loader (which it must be, otherwise your Main class cannot be loaded).






share|improve this answer





























    0














    You are loading the classes dynamically, thus, since you're able to compile class "Person", it means you're loading the same class twice, resulting in class cast exception.



    Remove the library from your classpath and you won't get this error however, you also will loose access to the Person object.



    Its still there when you load it, but the way to access it would be via Reflection, and you'll have to store the "Person" object as an "Object".






    share|improve this answer





















      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%2f53380178%2fclassloader-in-java%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      The formal documentation for the behaviour that you observe is in the ClassLoader#loadClass() documentation:




      Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:




      1. Invoke findLoadedClass(String) to check if the class has already been loaded.


      2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.


      3. Invoke the findClass(String) method to find the class.





      If you specify a parent class loader your URLClassLoader checks the parent class loader for the class before trying to load the class itself, which means that it will find the class from your application class path.



      So if you set the parent class loader, this line:



      Class<?> personClass = urlClassLoader.loadClass("com.test.Person");


      behaves the same as



      Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");


      if the class com.test.Person is available on the application class loader (which it must be, otherwise your Main class cannot be loaded).






      share|improve this answer


























        1














        The formal documentation for the behaviour that you observe is in the ClassLoader#loadClass() documentation:




        Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:




        1. Invoke findLoadedClass(String) to check if the class has already been loaded.


        2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.


        3. Invoke the findClass(String) method to find the class.





        If you specify a parent class loader your URLClassLoader checks the parent class loader for the class before trying to load the class itself, which means that it will find the class from your application class path.



        So if you set the parent class loader, this line:



        Class<?> personClass = urlClassLoader.loadClass("com.test.Person");


        behaves the same as



        Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");


        if the class com.test.Person is available on the application class loader (which it must be, otherwise your Main class cannot be loaded).






        share|improve this answer
























          1












          1








          1






          The formal documentation for the behaviour that you observe is in the ClassLoader#loadClass() documentation:




          Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:




          1. Invoke findLoadedClass(String) to check if the class has already been loaded.


          2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.


          3. Invoke the findClass(String) method to find the class.





          If you specify a parent class loader your URLClassLoader checks the parent class loader for the class before trying to load the class itself, which means that it will find the class from your application class path.



          So if you set the parent class loader, this line:



          Class<?> personClass = urlClassLoader.loadClass("com.test.Person");


          behaves the same as



          Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");


          if the class com.test.Person is available on the application class loader (which it must be, otherwise your Main class cannot be loaded).






          share|improve this answer












          The formal documentation for the behaviour that you observe is in the ClassLoader#loadClass() documentation:




          Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:




          1. Invoke findLoadedClass(String) to check if the class has already been loaded.


          2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.


          3. Invoke the findClass(String) method to find the class.





          If you specify a parent class loader your URLClassLoader checks the parent class loader for the class before trying to load the class itself, which means that it will find the class from your application class path.



          So if you set the parent class loader, this line:



          Class<?> personClass = urlClassLoader.loadClass("com.test.Person");


          behaves the same as



          Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");


          if the class com.test.Person is available on the application class loader (which it must be, otherwise your Main class cannot be loaded).







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 19 '18 at 18:11









          Thomas KlägerThomas Kläger

          6,1322718




          6,1322718

























              0














              You are loading the classes dynamically, thus, since you're able to compile class "Person", it means you're loading the same class twice, resulting in class cast exception.



              Remove the library from your classpath and you won't get this error however, you also will loose access to the Person object.



              Its still there when you load it, but the way to access it would be via Reflection, and you'll have to store the "Person" object as an "Object".






              share|improve this answer


























                0














                You are loading the classes dynamically, thus, since you're able to compile class "Person", it means you're loading the same class twice, resulting in class cast exception.



                Remove the library from your classpath and you won't get this error however, you also will loose access to the Person object.



                Its still there when you load it, but the way to access it would be via Reflection, and you'll have to store the "Person" object as an "Object".






                share|improve this answer
























                  0












                  0








                  0






                  You are loading the classes dynamically, thus, since you're able to compile class "Person", it means you're loading the same class twice, resulting in class cast exception.



                  Remove the library from your classpath and you won't get this error however, you also will loose access to the Person object.



                  Its still there when you load it, but the way to access it would be via Reflection, and you'll have to store the "Person" object as an "Object".






                  share|improve this answer












                  You are loading the classes dynamically, thus, since you're able to compile class "Person", it means you're loading the same class twice, resulting in class cast exception.



                  Remove the library from your classpath and you won't get this error however, you also will loose access to the Person object.



                  Its still there when you load it, but the way to access it would be via Reflection, and you'll have to store the "Person" object as an "Object".







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 19 '18 at 18:11









                  JoeJoe

                  387110




                  387110






























                      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%2f53380178%2fclassloader-in-java%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

                      MongoDB - Not Authorized To Execute Command

                      How to fix TextFormField cause rebuild widget in Flutter

                      Npm cannot find a required file even through it is in the searched directory