Ja.NET Standard Edition 5.0

Tools Documentation

Tools Main

How Assemblies are Found

Within the Ja.NET SE runtime infrastructure, we build and maintain an association between the loaded assemblies in the process and the Java class loaders running in the system. At any point in time, a given Java class loader can have zero or more assemblies associated with it, and any assembly will be associated with one and only one Java class loader. We maintain this association so that we can approximate the Java dynamic class loading and resolution behavior found in a standard Java platform. In this section, we describe how Ja.NET SE locates assemblies and how they become associated with class loaders. In the section on How Classes are Found, we describe how we use this infrastructure to dynamically link to classes at runtime.

When the Ja.NET SE runtime is first initialized, it creates a class loader hierarchy similar to what you find in a standard Java platform and initializes the assembly associations for each of the created loaders. The initial loader hierarchy contains the SE bootstrap class loader, followed by the extensions class loader as a sibling and then the system or application class loader as the extensions sibling. Of course as the application executes, other custom class loaders can also be created.

When the Ja.NET SE bootstrap loader is initialized, it makes a list of all currently loaded assemblies in the process and associates itself with each of them. Next, the extensions loader creates a list of all the assemblies located in the extensions directory (i.e., jre/lib/ext) and associates itself with each of them. Then finally, the system class loader associates itself with any assemblies included on the applications class path (i.e., java.class.path). At this point, from a Java runtime perspective, all of the classes contained in those assemblies have become scoped to their respective class loader.

As the Ja.NET based application continues to run, additional assemblies will become loaded into the process; the SE runtime dynamically determines with which class loader to associate the assembly. There are two situations the runtime must deal with when doing this: Those cases in which the .NET runtime loads assemblies without SE involvement; and, those cases in which SE is asked to locate and load an assembly.

The first case we�ll look at is the case in which the .NET runtime automatically loads an assembly without the involvement of Ja.NET SE. This typically happens as a result of .NET's own assembly probing algorithm. It can also occur as a result of a runtime call to a .NET framework API which explicitly loads an assembly. When this happens, the SE runtime has not been involved in the assembly resolution process or the loading of the assembly, but still needs to assign the assembly to some Java loader. This is necessary as the classes contained in the assembly need to be scoped to a class loader and also visible via Java API calls. In these situations, the SE runtime determines a loader using following algorithm:

The second case to look at are those situations in which Ja.NET SE is called upon to locate an assembly. This typically occurs as a result of the .NET runtime compiling a method to native code and encountering a reference to a field or a method that is scoped to an assembly that has not yet been loaded and it cannot find the assembly using its own probing algorithms. It can also occur when using the feature built into SE for supporting custom class loaders. To learn more on this, see our section, Custom Class Loaders in Ja.NET SE. Just as in the first case above, the SE runtime relies on the Java class loader hierarchy for help in locating the assembly. It uses Java�s standard class resolution algorithm, including honoring the parent relationship, by delegating to the parent first when searching for the assembly. It does this by first determining the class loader of the class that initiated the assembly resolution request, and then uses it as the starting point in the hierarchy for locating the assembly. The runtime walks up the hierarchy calling the findResource() method on each loader, passing the filename of the assembly for which it is searching. The first loader that returns a valid URL becomes the class loader with which assembly is associated. The SE runtime then loads the assembly into the process using the returned URL. If the assembly is not found, the runtime issues a NoClassDefFoundError exception on the thread.

As we mentioned in our section on .NET assembly usage, we have extended the syntax and semantics of the Java class path such that you can include assemblies on the class path, much like you do directories and jar files. As part of that extension, we have also enhanced the URLClassLoader included with SE to recognize URL's that refer to assemblies and to respond appropriately to the findResource() calls issued by the runtime. Of course if you have written a custom loader which subclasses URLClassLoader you will automatically inherit this behavior in your loader.

In addition, we have also ensured that the Java system class loader included in SE also responds appropriately to the findResource() calls issued by the runtime. This gives you the ability to simply add assemblies that your application will reference at runtime to the class path.  Those assemblies will then be found and loaded as required.