Velocity
  1. Velocity
  2. VELOCITY-196

ClasspathResourceLoader uses wrong ClassLoader

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.3.1
    • Fix Version/s: 1.5
    • Component/s: Engine
    • Labels:
      None
    • Environment:
      Operating System: other
      Platform: Other

      Description

      I see the following problems with ClasspathResourceLoader:

      1. It loads templates using the ClassLoader it was loaded in, which in many
      cases will be the top-level or a high-level ClassLoader within an appserver
      2. Individual applications within the server almost always are given their own
      contextual ClassLoader. In Tomcat, for example, each webapp has its own loader.
      3. Each webapp should be able to package templates in jars to be put in
      WEB-INF/lib and have Velocity load them correctly.
      4. Each webapp should not have to put velocity-xxx.jar in their WEB-INF/lib to
      be able to use Velocity.
      5. Therefore, Velocity should be able to load templates using the contextual
      ClassLoader appropriate for the caller

      ClasspathResourceLoader uses getClass().getClassLoader() to look for templates.
      If Velocity is loaded at the system or server level, and a webapp hopes to use
      this method to load its own jarred templates, it will fail as it did for me.

      The fix is terribly simple, and I think it makes sense to apply it directly to
      ClasspathResourceLoader, or at least provide a ThreadContextResourceLoader, as I
      have done:

      In ClasspathResourceLoader.getResourceStream(), change:

      ClassLoader classLoader = this.getClass().getClassLoader();

      to:

      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

      This will cause the resource loading to look first at the caller's level
      (webapp) and if not found, move up the ClassLoader chain. I believe this is the
      appropriate way to handle loading templates as resources. From the documentation
      for getContextClassLoader():

      ...

      • Returns the context ClassLoader for this Thread. The context
      • ClassLoader is provided by the creator of the thread for use
      • by code running in this thread when loading classes and resources.
      • If not set, the default is the ClassLoader context of the parent
      • Thread. The context ClassLoader of the primordial thread is
      • typically set to the class loader used to load the application.
        ...

      The resource should be loaded from the ClassLoader that the creator of the
      calling thread intended...not from the classloader that loaded Velocity. Also
      keep in mind this change would not break loading from the system classpath...it
      would just include contextual ClassLoaders in the lookup process.

      I will look into creating a patch if it would be useful, but it's a one-line fix.

      1. ASF.LICENSE.NOT.GRANTED--patch.txt
        1 kB
        Will Glass-Husain
      2. ASF.LICENSE.NOT.GRANTED--ClasspathFix.patch
        0.7 kB
        Charles Oliver Nutter

        Activity

          People

          • Assignee:
            Unassigned
            Reporter:
            Charles Oliver Nutter
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development