United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 6419145 JAXP fails to fall back properly when a non-standard class loader delegation is used
6419145 : JAXP fails to fall back properly when a non-standard class loader delegation is used

Details
Type:
Bug
Submit Date:
2006-04-27
Status:
Resolved
Updated Date:
2012-04-25
Project Name:
JDK
Resolved Date:
2006-07-17
Component:
xml
OS:
generic
Sub-Component:
javax.xml.transform
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:
6

Related Reports
Backport:
Relates:

Sub Tasks

Description
javax/xml/transform/FactoryFinder.java has the following part in the newInstance method:

  // Fall back to current classloader
  cl = FactoryFinder.class.getClassLoader();
  providerClass = cl.loadClass(className);

This code is used when the context class loader of the current thread fails to load the class.
When a class loader like the one in Tomcat is used (where they don't always delegate to the parent class loader),
this code is executed in the hope that this classloader can find the class.

Alas, when JAXP is in Tiger's rt.jar, FactoryFinder.class.getClassLoaer() returns null, so we'll get NPE.
The above code needs to be changed to:

  // Fall back to current classloader
  cl = FactoryFinder.class.getClassLoader();
  providerClass = Class.forName(className,true,cl);

See Class.forName javadoc for why this works correctly when cl==null and cl!=null.

I haven't checked, but I suspect this problem to apply to other FactoryFinders.

                                    

Comments
EVALUATION

I applied the patch suggested by Kohsuke to avoid a NPE. However, I believe there are a number of issues unresolved in relation to the FactoryFinder class. We may need to open another CR to address some inconsistencies in how the different factories in JAXP load classes and resources.
                                     
2006-06-23
EVALUATION

A related issue is the confusion around where the delegation is supposed to happen. For example, code like this (taken from FactoryFinder line 81:

            if (cl == null) {
                // If classloader is null Use the bootstrap ClassLoader.  
                // Thus Class.forName(String) will use the current
                // ClassLoader which will be the bootstrap ClassLoader.
                providerClass = Class.forName(className);
            } else {
                try {
                    providerClass = cl.loadClass(className);
                } catch (ClassNotFoundException x) {
                    if (doFallback) {
                        // Fall back to current classloader
                        cl = FactoryFinder.class.getClassLoader();
                        providerClass = cl.loadClass(className);
                    } else {
                        throw x;
                    }
                }
            }

assumes that when the context classloader is null, it uses the bootstrap classloader (since Class.forName uses the caller's classloader, which is bootstrap loader.)  Yet in some other places, such as in SecuritySupport (line 77)

    InputStream getResourceAsStream(final ClassLoader cl,
                                           final String name)
    {
        return (InputStream)
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    InputStream ris;
                    if (cl == null) {
                        ris = ClassLoader.getSystemResourceAsStream(name);
                    } else {
                        ris = cl.getResourceAsStream(name);
                    }
                    return ris;
                }
            });
    }

... it delegates to the system classloader. So if my context classloader is null, JAXP may find META-INF/services from my system classloader, yet it will fail to load it from the bootstrap classloader (as the implementation was in my system classpath, not bootstrap.)
                                     
2006-06-21
EVALUATION

this CR is similar to 6350682: REGRESSION: SAXParserFactory throws FactoryConfigurationError if contextClassLoader=null

note that classloading has security implicatitons.
the JAXP team has a query in with the security team as to a proper fix.
                                     
2006-04-27



Hardware and Software, Engineered to Work Together