Finding Factory Classes in JAXP
The JAXP API defines a pluggability layer which allows easy swapping of implementations via the use of system properties and meta-information stored in JAR files. I have recently found that the mechanism by which factory classes are located and loaded still causes a great deal of confusion. I've recently cleaned up this code in JAXP 1.4, available as part of J2SE 6.0 (Mustang), and decided to write a blog explaining how this works.
There are several factory classes in JAXP, but aside from a few exceptions, they all find and load implementations in a similar manner. For simplicity, I'll focus on one of the most popular ones: the SAXParserFactory class. In J2SE 6.0, this class provides two static methods that return an instance of the underlying implementation class:
public static SAXParserFactory newInstance();
public static SAXParserFactory newInstance(String factoryClassName,
The signatures of these methods are self explanatory: the first method simply returns an instance without any additional information passed by the user, while the latter accepts a factory name and a class loader to be used for actually loading the class.
When no factory name is provided, the pluggability layer in JAXP finds the name of the SAX factory class in the following order:
- By checking the value of the property javax.xml.parsers.SAXParserFactory
- If that fails, by checking the value of javax.xml.parsers.SAXParserFactory after loading the properties file java.home/lib/jaxp.properties
- If that fails, by using the Jar Service Provider mechanism, which essentially amounts to inspecting all the jars in the class path looking for the META-INF/services/javax.xml.parsers.SAXParserFactory resource.
Note that the file java.home/lib/jaxp.properties is only loaded once during the lifetime of the VM. Despite that, the process of finding factory classes can be time consuming, especially when all the jar files in a class path have to be inspected.
Many applications out there set the value the property javax.xml.parsers.SAXParserFactory from the command line, to force the VM to use a specific factory implementation. In general, this is not good practice, especially in applications such as web containers where it is likely for different applications to rely on different factory implemenations. If a certain application only works with a SAX parser from vendor X, you're likely better off by completely bypassing the pluggability layer and creating the factory instance directly using new.
So far, we've described how classes are located, but how are they actually loaded? Before getting into this discussion, we need to briefly cover the topic of class loaders in Java. There are numerous articles on the Web that describe the various class loaders available in Java, so I won't try to explain all of them here. For the purpose of this discussion, we need to familiarized ourselves with the bootstrap class loader, the context class loader and the current class loader. Since these names tend not be used to refer to exactly the same concept in the literature, I'll briefly explain each of them next.
The bootstrap class loader is used to load all the platform class (think rt.jar) and it is, therefore, the one used to load the JAXP API classes in J2SE 6.0. The context and current class loaders have multiple personalities and depend on, you guessed it, the context and the current class. The context class loader can be obtained by calling Thread.currentThread().getContextClassLoader and it is typically used by application containers to provide boundaries between hosted applications (recall that two classes are equal only if they were loaded by the same class loader). The current class loader refers to that used to load the class that is issuing the loading request. The current class loader is typically exercised by calling Class.forName(String).
Since the JAXP API classes are loaded by the bootstrap class loader, it follows that current class loader in this API classes is just the bootstrap class loader.
As a rule of thumb when no class loader is provided by the user, the JAXP API will attempt to use the context class loader first, falling back to the current class loader (i.e., the bootstrap class loader in J2SE 6.0) if either the context class loader is undefined (i.e., set to null) or if it is unable to load the class. When a class loader is provided by the user, then there's currently no fallback mechanism (although this may change in future!) and an error is reported if that class loader is unable to find the class. An exception to the last rule is when null is passed in place of a legitimate class loader, in which case the bootstrap class loader is used given that, perhaps unfortunately, null is also used to represent the bootstrap class loader.
Class loaders and the class loader delegation model --which I didn't even talk about-- are very powerful concepts in Java. But at the same time introduce additional complexity which is difficult to master at first. Hopefully this blog will shed some light on how classes are located and loaded in JAXP. Yet, for some reason, I feel this won't be my last blog about the topic :-)