# Friday, 26 October 2007
« New Development Snapshot | Main | Development Snapshot Update »
Writing a Custom Assembly Class Loader

A new development snapshot. It's now possible to write your own custom assembly class loader. This is the recommended pattern:

class MyCustomClassLoader extends ClassLoader
{
  MyCustomClassLoader(cli.System.Reflection.Assembly asm)
  {
    super(new ikvm.runtime.AssemblyClassLoader(asm));
  }

  protected Class findClass(String name)
  {
    // TODO: forward call to other class loader or load class and call defineClass()
  }

  protected URL findResource(String name)
  {
    // TODO: forward call to other class loader or find resource somewhere
  }

  protected Enumeration findResources(String name)
  {
    // TODO: forward call to other class loader or find resources somewhere
  } 
}

If you delegate to other class loaders, you should be careful to avoid loops in the delegation path. If you want to change the resource loading delegation order, you can override getResource[s]() instead of findResource[s]() relatively safely, but if you want to change the delegation order for classes you need to be more careful, because you cannot replace any classes that are defined in the assembly.

Of course, you can also reuse existing class loader classes. Here's an example with URLClassLoader:

class MyCustomClassLoader extends java.net.URLClassLoader
{
  MyCustomClassLoader(cli.System.Reflection.Assembly asm)
  {
    super(new java.net.URL[0], new ikvm.runtime.AssemblyClassLoader(asm));
    // see below why calling addURL() is safer than passing it to the super constructor
    addURL(new java.net.URL("..."));
  }
}

Note that custom assembly class loader classes and their single argument Assembly constructor must be accessible from the assembly that they are applied to.

Delegation Magic

The ikvm.runtime.AssemblyClassLoader instance that is passed in as the parent class loader is a bit funny. It supports loading classes and resources from the assembly, but it effectively does this by magically delegating back to the custom class loader (without actually calling it, otherwise you'd get infinite recursion.) This means that classes from the assembly can be loaded via the parent class loader, but they report the custom class loader instance as their class loader.

Construction Magic

The custom assembly class loader is constructed when someone calls getClassLoader() on a class defined in that assembly for the first time, but what should getClassLoader() return while the custom class loader is being constructed? For consistencies sake, I've decided to apply some magic here and to make it return the object that is currently being constructed. This implies that you should call the base class constructor ASAP, because as long as you haven't done this the ClassLoader instance is in an unitialized state. After calling the base class constructor you can do additional work to configure your custom class loader, but you should take into account that while you are setting up your instance data, if you do anything that causes a class or resource to be loaded via your class loader, that your methods may run while initialization has not yet been completed. Note that this can only happen for the initiating thread. All other threads that call getClassLoader() will be blocked while the constructor is runnning. If the constructor throws an exception, the initiating call to getClassLoader() will see the exception, but all other calls will return the partially initialized class loader object.

Too Much Magic?

I certainly hope not, but I have to admit this is a scary feature. I recommend only writing your own custom assembly class loader if you really understand Java class loaders and there is no alternative.

Finally, please do send me feedback on this feature (even if it's a simple "I like it" or "It sucks"). I plan on backporting this to the 0.36 release, so it's important to get this right.

Changes:

  • More changes to keep up the pretense that an AssemblyClassLoader has already loaded all classes in the assembly.
  • Made AssemblyClassLoader public and moved it to ikvm.runtime package.
  • Allow non-public custom assembly class loaders (if they are defined in the same assembly).
  • Fixed ClassLoader.getSystemClassLoader() to return the custom assembly class loader for the main executable, if one is defined, even if the java.class.path or java.ext.dirs system property is set.
  • Restructured AssemblyClassLoader.GetProtectionDomain() to avoid calling any code while holding the lock.

Binaries available here: ikvmbin-0.37.2855.zip.

Friday, 26 October 2007 11:25:23 (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]
Saturday, 13 December 2008 21:54:08 (W. Europe Standard Time, UTC+01:00)
this is absolutely neat, I like it!
Franco
Thursday, 29 January 2009 14:16:18 (W. Europe Standard Time, UTC+01:00)
Does this still works in release 0.38.0.2? I'm having trouble with the following line:

new ikvm.runtime.AssemblyClassLoader(asm)

It looks like the class AssemblyClassLoader is now in ikvm.internal.AssemblyClassLoader but the source code file in classpath/ikvm/internal/AssemblyClassLoader.java still has package ikvm.runtime which is a compilation error...
Thursday, 29 January 2009 14:24:24 (W. Europe Standard Time, UTC+01:00)
You probably need to run ikvmstub on IKVM.OpenJDK.ClassLibrary.dll and add the resulting jar to your classpath instead of the ikvm directory.
Wednesday, 06 October 2010 23:23:36 (W. Europe Daylight Time, UTC+02:00)
using IKVM to cross compile our java app. Having issues with pring beans not finding classes from assemblies. if we start fresh then it looks like our assemblies load as expected but. if there is an iisreset issued the assemblies seem to not completely load from the .NET temp directory and we get class not found. we tied manually loading the dlls from the bin dir but then we end up with class cast issue from the class being loaded from the temp dir. our spring configs are the same in java they don't have the .net style syntax. any help would be appreciated
Tim Cronin
Name
E-mail
Home page

I apologize for the lameness of this, but the comment spam was driving me nuts. In order to be able to post a comment, you need to answer a simple question. Hopefully this question is easy enough not to annoy serious commenters, but hard enough to keep the spammers away.

Anti-Spam Question: What method on java.lang.System returns an object's original hashcode (i.e. the one that would be returned by java.lang.Object.hashCode() if it wasn't overridden)? (case is significant)

Answer:  
Comment (HTML not allowed)  

Live Comment Preview