9 Replies Latest reply on Feb 10, 2009 11:50 AM by jhalliday

    classloading dependencies

    jhalliday

      I'm trying to deploy a .jar in AS 5. It contains a bean, let's call it fooBean, that links against class barClass. barClass is not in the .jar, it's in barModule. So at first I try

      <bean name="fooBean" class="fooBean">
       <depends>barModule</depends>
      


      which results in a ClassDefNotFound. Apparantly MC tries to classload the fooBean even though barModule does not yet exist. So I rant a bit about how unintuitive that is, then try to add a jboss-classloading.xml:

      <classloading xmlns="urn:jboss:classloading:1.0" export-all="NON_EMPTY">
       <requirements>
       <package name="org.jboss.bar"/>
       </requirements>
      </classloading>
      


      which at least prevents deployment until barModule is present, but then throws

      java.lang.NullPointerException
       at org.jboss.classloading.spi.dependency.ClassLoadingSpace.resolve(ClassLoadingSpace.java:325)
       at org.jboss.classloading.spi.dependency.Module.resolveModule(Module.java:737)
       at org.jboss.classloading.spi.dependency.RequirementDependencyItem.resolve(RequirementDependencyItem.java:87)
      


      Apparently barModule.getClassLoadingSpace() returns null.

      So now I'm stuck. What's the correct way to solve this dependency problem?

        • 1. Re: classloading dependencies

           

          "jhalliday" wrote:
          I'm trying to deploy a .jar in AS 5. It contains a bean, let's call it fooBean, that links against class barClass. barClass is not in the .jar, it's in barModule. So at first I try

          <bean name="fooBean" class="fooBean">
           <depends>barModule</depends>
          


          which results in a ClassDefNotFound. Apparantly MC tries to classload the fooBean even though barModule does not yet exist. So I rant a bit about how unintuitive that is,


          A depends is for the create/start stages of the lifecycle
          which is much too late for a classloading dependency.

          You want to use a demand to stop the bean from being analysed for annotations
          during initial installation.

          <bean name="fooBean" class="fooBean">
           <demand state="PreInstall">barModule</demand>
          



          then try to add a jboss-classloading.xml:

          <classloading xmlns="urn:jboss:classloading:1.0" export-all="NON_EMPTY">
           <requirements>
           <package name="org.jboss.bar"/>
           </requirements>
          </classloading>
          


          which at least prevents deployment until barModule is present, but then throws

          java.lang.NullPointerException
           at org.jboss.classloading.spi.dependency.ClassLoadingSpace.resolve(ClassLoadingSpace.java:325)
           at org.jboss.classloading.spi.dependency.Module.resolveModule(Module.java:737)
           at org.jboss.classloading.spi.dependency.RequirementDependencyItem.resolve(RequirementDependencyItem.java:87)
          


          Apparently barModule.getClassLoadingSpace() returns null.

          So now I'm stuck. What's the correct way to solve this dependency problem?


          That's already been fixed:
          https://jira.jboss.org/jira/browse/JBCL-77

          • 2. Re: classloading dependencies
            jhalliday

            > state="PreInstall"

            Ahh, so it's a case of the implicit state not being what I expect. Explicitly specifying a sufficiently early state in the -beans.xml provides an alternative to using a -classloading.xml. Cool.

            > That's already been fixed

            .. but the fix is not in AS branch 5.x yet. Fair enough. Thanks for the help.

            One further question: Assuming I have a choice between the -beans.xml and -classloading.xml techniques for specifying the dependency, what is considered best practice? This is for a transactions demo app we'll be shipping from JBoss, so if there is a 'right way' of doing things I guess I should use it :-)

            • 3. Re: classloading dependencies
              alesj

               

              "jhalliday" wrote:

              One further question: Assuming I have a choice between the -beans.xml and -classloading.xml techniques for specifying the dependency, what is considered best practice?

              I would go with -classloading.xml as that *clearly* states cl dependency.

              The -beans.xml way depends on "nobody doing any cl-ing before PreInstall",
              which might change if you dynamically add some state before PreInstall who's
              action is already gonna touch some BeanInfo/ClassInfo stuff.


              • 4. Re: classloading dependencies

                 

                "jhalliday" wrote:

                > That's already been fixed

                .. but the fix is not in AS branch 5.x yet.


                The fix is in Branch_5_0

                12:54:24,440 INFO [ServerImpl] Release ID: JBoss [Morpheus] 5.0.1.GA (build: SVNTag=JBoss_5_0_1_GA date=200902091457)
                <snip/>
                12:54:32,351 WARN [RequirementDependencyItem] VFSClassLoaderPolicyModule bindings-classloader:0.0.0 resolved ModuleRequirement{jmx-classloader [0.0.0,?)} to VFSClassLoaderPolicyModule jmx-classloader:0.0.0 which has import-all=true. Cannot check its consistency.
                



                One further question: Assuming I have a choice between the -beans.xml and -classloading.xml techniques for specifying the dependency, what is considered best practice? This is for a transactions demo app we'll be shipping from JBoss, so if there is a 'right way' of doing things I guess I should use it :-)


                Best practice is to depend upon packages rather than modules
                because it is less susceptable to refactoring problems.
                That requires the jboss-classloading.xml

                • 5. Re: classloading dependencies
                  jhalliday

                  Whilst waiting for the fix to make its way into branch 5.x I used the

                  <demand state="PreInstall">barModule</demand>


                  approach instead.

                  This correctly prevents a classloading attempt when barModule is not present.

                  However, when the module is present the ClassDefNotFound comes back.

                  I'm guessing barModule's classes are not exposed to other modules by default? If I don't control barModule, is there any way I can still get at its classes, short of copying the .jar files? :-)

                  Failing that, what's the correct meta data for barModule to expose things? jboss-classloading.xml with capabilities elements for anything it wants to publish?

                  • 6. Re: classloading dependencies
                    alesj

                     

                    "jhalliday" wrote:

                    I'm guessing barModule's classes are not exposed to other modules by default?

                    They should be, as that's the old JBoss cl behavior (which is still there by default).
                    "Big ball of mud" as Adrian calls it. :-)

                    • 7. Re: classloading dependencies
                      kabirkhan

                       

                      "alesj" wrote:
                      "jhalliday" wrote:

                      I'm guessing barModule's classes are not exposed to other modules by default?

                      They should be, as that's the old JBoss cl behavior (which is still there by default).
                      "Big ball of mud" as Adrian calls it. :-)

                      I think for that to work, you need to set importAll on the requesting classloader?

                      • 8. Re: classloading dependencies
                        alesj

                         

                        "kabir.khan@jboss.com" wrote:

                        I think for that to work, you need to set importAll on the requesting classloader?

                        Sure.
                        But this is done via this
                         <bean name="ClassLoadingDefaultDeployer" class="org.jboss.deployers.plugins.classloading.ClassLoadingDefaultDeployer">
                         <property name="defaultMetaData">
                         <classloading xmlns="urn:jboss:classloading:1.0" export-all="NON_EMPTY" import-all="true"/>
                         </property>
                         </bean>
                        


                        So, unless you have some other means of creating CLMD,
                        this will kick in, mocking the old behavior.

                        • 9. Re: classloading dependencies
                          jhalliday

                          Ahh, I had a jboss-classloading.xml left over from the earlier experiment. It does not have a requirements bit at the moment, but it does have

                          <classloading xmlns="urn:jboss:classloading:1.0" export-all="NON_EMPTY">


                          which seems to override the default behaviour even though it's missing any explicit import-all clause. Changing to

                          <classloading xmlns="urn:jboss:classloading:1.0" export-all="NON_EMPTY" import-all="true">


                          makes it behave the way I want.

                          Thanks for the help.