7 Replies Latest reply on Oct 20, 2011 12:00 PM by mandrosen

    loading class from WEB-INF/classes from xwork ClassFinder

    mandrosen

      I am having a problem loading classes in the WEB-INF/classes directory in 7.0.2.Final.

      I am using struts2 and trying to use the convention plugin which scans classes in that directory for annotations.  Everything works fine, including these classes (meaning I can call the actions from web pages), but the annotations are never read, and I get this error, when the plugin tries to scan the classes:

      Unable to read class [WEB-INF.classes.com.at.email.web.action.HomeAction]: Could not load STILL WEB-INF/classes/com/at/email/web/action/HomeAction.class - [unknown location]

       

      I don't think it is directly related to xwork, because it is just calling ModuleClassLoader.getResource([classname]).

       

      The only way I can get the class to load and the annotations to work is to load it this way:

       

      URL resource = new URL("file", null, "/C:/jboss/jboss-as-7.0.2.Final/standalone/deployments/email.ear/emailWeb.war/" + [classname]);

       

      Is there any reason why that class is not loadable at that point?

        • 1. Re: loading class from WEB-INF/classes from xwork ClassFinder
          jaikiran

          It depends on how that XWork code tries to load that class. Do you have snippet which shows how it's done? I suspect it isn't able to handle the VFS URL returned.

          • 2. Re: loading class from WEB-INF/classes from xwork ClassFinder
            mandrosen

            <code>

             

                private void readClassDef(String className) {

                    if (!className.endsWith(".class")) {

                        className = className.replace('.', '/') + ".class";

                    }

                    try {

                        URL resource = classLoaderInterface.getResource(className);

                        if (resource == null) {

                                  resource = new URL("file", null, "/C:/jboss/jboss-as-7.0.2.Final/standalone/deployments/email.ear/emailWeb.war/" + className);

                        }

                        if (resource != null) {

                            InputStream in = resource.openStream();

                            try {

                                ClassReader classReader = new ClassReader(in);

                                classReader.accept(new InfoBuildingVisitor(), ClassReader.SKIP_DEBUG);

                            } finally {

                                in.close();

                            }

                        } else {

                            throw new XWorkException("Could not load STILL " + className);

                        }

                    } catch (IOException e) {

                        throw new XWorkException("Could not load " + className, e);

                    }

             

             

                }

             

             

            </code>

             

            The className parameter is WEB-INF.classes.com.at.email.action.HomeAction.class, so it gets changed to 'WEB-INF/classes/com/at/email/action/HomeAction.class'.  That comes from the application, but I experimented with dropping the WEB-INF/classes too.  The classLoaderInterface is just a classloader delegate and the classLoader that it is using is the ModuleClassLoader.  I also tried using Thread.currentThread().getContextClassLoader(), but I get the same MuduleClassLoader. 

             

            Maybe I need to convert the 'WEB-INF/classes/...' to a VFS url?

            • 3. Re: loading class from WEB-INF/classes from xwork ClassFinder
              alesj

              This all looks like bunch of massive hacks. :-)

              What exactly are you trying to do?

               

              I guess your goal is to get class's bytes (via stream) before it's loadled?

              (or you don't care if it's loaded before?)

              • 4. Re: loading class from WEB-INF/classes from xwork ClassFinder
                mandrosen

                You are correct about wanting to read the class presumably before it is loaded.  I checked the classes that are loaded by classLoader at this point and it includes many classes from the xwork and struts jars, some classes from my application, but not this class (or other similar ones).

                 

                The only part I added was this:

                 

                <code>resource = new URL("file", null, "/C:/jboss/jboss-as-7.0.2.Final/standalone/deployments/email.ear/emailWeb.war/" + className);</code>

                 

                It's not intended to be working code, just to prove to myself that the file is actually accessible in some way.  The rest of the code comes from xwork and it is unable to load the class.  I know the class is loadable later in the process (this code is called at startup searching for annotations), because the the action works. 

                 

                I thought of ways of determing how to get that point programmatically by searching System properties for jboss directories and JNDI for deployed applications, but they are also not ideal.  Really I am interested in why the the method ModuleClassLoader.getResource(className) does not work at this point and what I can do to make it work (besides hard coding the location).

                • 5. Re: loading class from WEB-INF/classes from xwork ClassFinder
                  alesj

                  Really I am interested in why the the method ModuleClassLoader.getResource(className) does not work at this point and what I can do to make it work (besides hard coding the location).

                  I doubt the classloader exposes its classes via getResource.

                  I know we didn't do it JBossAS5/6.

                  Cannot remember the exact reason atm, but I know it made sense.

                  (the ClassLoader::getResource doesn't explicitly forbid, but doesn't mention classes as possible resources ...)

                   

                  You will probably need to plugin at a different level, as this way it looks like you're too dependent on impl details of CL layer.

                  • 6. Re: loading class from WEB-INF/classes from xwork ClassFinder
                    dmlloyd

                    You can load class bytes from the module CL via classLoader.getResource("org/foo/your/Clazz.class").  But you are not going to have any guarantee that the URL which is returned is a browseable directory or anything like that.

                    • 7. Re: loading class from WEB-INF/classes from xwork ClassFinder
                      mandrosen

                      That works.  Thanks.  I modified their code and added:

                       

                      <code>

                      if (resource == null && StringUtils.contains(className, "WEB-INF/classes")) {

                        resource = classLoaderInterface.getResource(StringUtils.substringAfter(className, "WEB-INF/classes"));

                      }

                      </code>