1 2 Previous Next 16 Replies Latest reply on Jan 12, 2010 8:51 AM by adrian.brock

    Doble ear Classloader problem

    igor84

      I am using jboss 5.0.1 and deploying epps.ear application to it. From time to time I get this exception:

       

      java.lang.ClassCastException: org.jdom.Document cannot be cast to org.jdom.Element
      at org.jaxen.jdom.DocumentNavigator.getDocumentNode(DocumentNavigator.java:397)
      at org.jaxen.expr.DefaultAbsoluteLocationPath.evaluate(DefaultAbsoluteLocationPath.java:102)
      at org.jaxen.expr.DefaultXPathExpr.asList(DefaultXPathExpr.java:102)
      at org.jaxen.BaseXPath.selectNodesForContext(BaseXPath.java:674)
      at org.jaxen.BaseXPath.selectNodes(BaseXPath.java:213)
      at org.jaxen.BaseXPath.selectSingleNode(BaseXPath.java:234)
      at org.jdom.xpath.JaxenXPath.selectSingleNode(JaxenXPath.java:153)...

       

      Method where this exception occurs is (I added try catch System.out part):

       

      public Object getDocumentNode(Object contextNode)
          {
              try {
                  if ( contextNode instanceof Document )
                  {
                      return contextNode;
                  }
         
                  Element elem = (Element) contextNode;
         
                  return elem.getDocument();
              } catch (ClassCastException ce) {
                  System.out.println("Given object class: "+contextNode.getClass().getName()+" classloader:"+contextNode.getClass().getClassLoader()+" parent classloader"+contextNode.getClass().getClassLoader().getParent());
                  System.out.println("My Document class: "+Document.class.getName()+" classloader:"+Document.class.getClassLoader()+" parent classloader"+Document.class.getClassLoader().getParent());
                  throw ce;
              }
          }

       

      And System.out.println that I added gives me this:

       

      Given object class: org.jdom.Document classloader:BaseClassLoader@18f3ba1{vfsfile:/C:/serveri/jboss-5.0.1.GA/server/default/deploy/epps.ear/} parent classloadernull
      My Document class: org.jdom.Document classloader:BaseClassLoader@12f95de{vfsfile:/C:/serveri/jboss-5.0.1.GA/server/default/deploy/epps.ear/} parent classloadernull

       

      If I am reading this correctly there are two BaseClassLoader instances and both loaded jdom classes so instanceof operator thinks that given org.jdom.Document is not the same class as its org.jdom.Document.

       

      Does anyone have an idea how could this have happened and how can I stop it from happening? Tell me if you need any further informations. Thank you.

        • 1. Re: Doble ear Classloader problem
          jaikiran
          1 of 1 people found this helpful
          • 2. Re: Doble ear Classloader problem
            alesj

            You have org.jdom.Document class in two locations.

            * one with your app

            * the other one somewhere in JBoss libs

             

            Either configure your classloading properly - depending on which version you wanna to pick up,

            but it's usually easier to just remove one of them - probably in your app, as we don't know who all depends on it inside JBossAS.


            • 3. Re: Doble ear Classloader problem
              igor84
              No this is not the case. I checked many times but I only have this class in one jar that is under <JBOSS_HOME>/common/lib. It seams that this error is only encountered after hot redeploys are done.
              • 4. Re: Doble ear Classloader problem
                alesj
                It seams that this error is only encountered after hot redeploys are done.

                Where exactly is this code (structure wise)? And what does it do?

                Although I don't see how/where would we keep stale classloader ...

                • 5. Re: Doble ear Classloader problem
                  alesj

                  Although I don't see how/where would we keep stale classloader ...

                  Specially since Classloader for this class - which you say is in JBOSS_HOME/common/lib - never gets redeployed.

                  (this classloader is created as part of conf/jboss-service.xml deployment -- see its classpath element)

                  So, you should always get the same class no matter what you do -- unless duplicates are present ...

                  • 6. Re: Doble ear Classloader problem

                    Can you change your System.out.println() to show the

                     

                    Class.getProtectionDomain().getCodeSource().getLocation()

                     

                    for the contextNode.getClass() and Document.class.

                     

                    You could also try the trick:

                    ((org.jboss.classloader.spi.base.BaseClassLoader) classloader).listPolicyDetails();

                    which will give you a lot more information but it means compiling over the jboss classes unless you do it via reflection.

                     

                    Assuming they are not the same, it will tell you where each comes from. It means you have a scoping problem,

                    where different classes/applications see different versions of the jdom classes and are passing by reference.

                    The links posted above explain that in more detail.

                     

                    If they are the same, then it means you're leaking classes across hot deployments,

                    e.g. passing Document implementations to something that is not getting redeployed and then asking for it back once you've redeployed

                    the Document class. A heap dump should tell you what is holding onto old references to the classes.

                    1 of 1 people found this helpful
                    • 7. Re: Doble ear Classloader problem
                      igor84
                      Sorry, I wasn't clear. Class org.jaxen.jdom.DocumentNavigator where exception occures is in <JBOSS_HOME>/common/lib/jaxen.jar and org.jdom.Document class is in <JBOSS_HOME>/server/default/deploy/epps.ear/lib/jdom.jar. So when redeploy is done org.jdom.Document is redeployed also. I tried some of the settings from above links but they didn't help. Only solution I haven't try yet is to move jdom.jar to /common/lib also. I am pretty sure this will solve this problem, but is it the right way to solve it?
                      • 8. Re: Doble ear Classloader problem
                        alesj
                        Sorry, I wasn't clear. Class org.jaxen.jdom.DocumentNavigator where exception occures is in <JBOSS_HOME>/common/lib/jaxen.jar and org.jdom.Document class is in <JBOSS_HOME>/server/default/deploy/epps.ear/lib/jdom.jar. So when redeploy is done org.jdom.Document is redeployed also.

                        Now this looks more like what Adrian suspects:

                         

                        If they are the same, then it means you're leaking classes across hot deployments,
                        e.g. passing Document implementations to something that is not getting redeployed and then asking for it back once you've redeployed
                        the Document class. A heap dump should tell you what is holding onto old references to the classes.


                        Can you try Adrian's debug/log suggestions so we know a bit more.

                        • 9. Re: Doble ear Classloader problem
                          igor84
                          I did a heap dump after hot redeploy and analyse it using Eclipse Memory Analyzer Tool. There were two org.jdom.Document classes. One had two objects and the other one had three objects. I found that some classes were holding references to these objects in static fields. I used ApplicationLifecycleListener.contextDestroyed to release these references. I again did redeploy and heap dump. There are still two org.jdom.Document classes but one has no objects now. I still get ClassCastException. I listed all objects of org.jboss.classloader.spi.base.BaseClassLoader and there are a lot. For each I looked at policy.name value. Every BaseClassLoader has unique value except two. There are two BaseClassLoader objects for policy.name=epps.ear and two BaseClassLoader objects for policy.name=epps-web.war.
                          • 10. Re: Doble ear Classloader problem
                            alesj

                            What does this "contextNode.getClass().getProtectionDomain().getCodeSource().getLocation()" and

                            "Document.class.getProtectionDomain().getCodeSource().getLocation()" print out in your try/catch?

                            • 11. Re: Doble ear Classloader problem
                              igor84

                              This code:

                               

                              CodeSource cs = contextNode.getClass().getProtectionDomain().getCodeSource();
                              System.out.println("Given object class: "+ ((cs==null)? "CodeSource is null": cs.getLocation().toString()));
                              cs = Document.class.getProtectionDomain().getCodeSource();
                              System.out.println("My Document class: "+ ((cs==null)? "CodeSource is null": cs.getLocation().toString()));

                               

                              returned:

                               

                              11:36:14,421 INFO  [STDOUT] Given object class: jar:file:/C:/servers/jboss-5.0.1.GA/server/default/deploy/epps.ear/lib/jdom.jar!/
                              11:36:14,421 INFO  [STDOUT] My Document class: jar:file:/C:/servers/jboss-5.0.1.GA/server/default/deploy/epps.ear/lib/jdom.jar!/
                              • 12. Re: Doble ear Classloader problem
                                alesj
                                You are leaking classes -- as Adrian figured out -- do proper cleanup on re-deploy.
                                • 13. Re: Doble ear Classloader problem
                                  igor84
                                  But how? I already said I released the objects of org.jdom.Document on redeploy, but Class instance still exists and so does a BaseClassLoader that loaded it.
                                  • 14. Re: Doble ear Classloader problem
                                    alesj

                                    Looks like you don't cleanup enough.

                                    e.g. some other deployment might hold on to the old ref

                                    1 2 Previous Next