Class loading and OSGi

SaxonJ runs in a wide variety of Java environments without problems, but problems can occasionally arise because of the specialized requirements of particular platforms. This is particularly true of environments that have their own way of doing Java class loading (examples are Eclipse and Apache Camel).

As a general rule, arbitrary failures can arise if more than one SaxonJ version is on the classpath. This applies both across versions (for example SaxonJ 10 and SaxonJ 9.9) and across editions (say SaxonJ-EE and SaxonJ-HE). Note that although there are many classes (such as net.sf.saxon.Configuration) which are present in all three SaxonJ editions (HE, PE, EE) the actual content of the class may vary slightly between editions, which is why mixing classes loaded from different editions is generally fatal.

JAXP provides the ability to load parsers, XSLT transformation engines, XPath processors, and schema processors by searching the classpath for a JAR file that declares itself appropriately as a service provider. The intent of this mechanism is that applications can switch from one processor to another simply by changing what JAR files are on the classpath. In Saxonica's experience this mechanism can often cause problems, because the level of compatibility between different providers is not good enough. If an XSLT stylesheet has been tested under Xalan, for example, there are many reasons why it might not work under Saxon (or vice versa): the products implement different versions of the W3C specifications, many features of the W3C specifications have been left implementation-defined (for example, vendor extension functions), and even at the API level, products are in many cases allowed to interpret the specifications in their own way. Therefore Saxonica recommends that applications should explicitly load a software package that has been tested with the application and is known to work, rather than allowing a different provider to be substituted simply by changing the classpath.

SaxonJ uses dynamic loading to access resources in a number of situations, for example:

  • Locating the license file for SaxonJ-PE and SaxonJ-EE
  • Loading user-supplied extension functions
  • Loading copies of commonly-used W3C schemas and DTDs (issued within the Saxon JAR file in folder net/sf/saxon/data)
  • Invoking "plugins" of various kinds, such as localization code, collations, URI resolvers, non-standard XML parsers

Generally all such dynamic loading is channeled via a DynamicLoader object obtained as a property of the Configuration. Applications with specialist requirements can either customize Saxon's DynamicLoader (for example by calling configuration.getDymanicLoader().setClassLoader()), or they can replace Saxon's DynamicLoader with one of their own.

By default, Saxon's DynamicLoader uses the following strategy to load a class, in order:

  1. Check if the class is present in a list of known, pre-registered classes, and if so, return the known class.
  2. Use any ClassLoader that has been explicitly registered using DynamicLoader.setClassLoader().
  3. Use the context class loader for the current thread.
  4. Use Class.forName().

This strategy sometimes fails in environments that use OSGi (for example Apache Camel). Saxon does not explicitly support OSGi. In some cases users have reported that a sufficient workaround is to call configuration.getDynamicLoader().setClassLoader(Configuration.class.getClassLoader());.

See also Troubleshooting license file problems.