# Friday, 18 August 2006
« IKVM 0.30 Released | Main | New Snapshot »
Breaking Changes

Now that 0.30 has been released, it's time to talk about the next version. While 0.30 was baking, I've made some significant changes. People sometimes ask me why the version number is so low, part of the reason is that I anticipate that I'll need to make breaking changes a couple more times.

Moved Runtime API to IKVM.GNU.Classpath.dll

To make the runtime API easier to use and to allow (potential) future changes that remove the need for IKVM.Runtime.dll to discover IKVM.GNU.Classpath.dll, I moved the public API of the runtime into IKVM.GNU.Classpath.dll. Now, IKVM.Runtime.dll still exposes a bunch of public types, but you should not use any of these, they are "undocumented" and only for use by ikvmc generated code and IKVM.GNU.Classpath.dll. They will also change in future versions.

Revisiting the ClassLoader per Assembly Idea

Over the past couple of years I've slowly come around on my initial decision to have all classes in assemblies appear to be loaded by the boot class loader. My initial reluctance was mostly due to the fact that using a ClassLoader per assembly would require violating the ClassLoader delegation model, but the success of OSGi (which does the same) demonstrates that this isn't such a big deal.

Here are some of the advantages:

  • Each assembly will be its own namespace, meaning that things like Class.forName() and Class.getResource() will be able to search the calling assembly first, so you won't get into class or resource name conflicts as easily.
  • It removes the need for the hack that returns the system class loader, instead of null, for statically compiled classes.
  • It allows for many operations to be more efficient.
  • It removes the need for pre-loading assemblies to make Class.forName() work, because the assembly class loader will be able to search all referenced assemblies (i.e. ikvmc's -reference option will be honored by the assembly class loader).
  • You will be able to take full advantage of .NET assembly namespace separation (i.e. multiple versions of a jar can be compiled and used in the same AppDomain, by different pieces of code).
  • It allows for a more natural integration of ReflectionOnly support (when running a .NET 2.0 build of ikvmc or ikvmstub).

I made a new snapshot that you can play around with to evaluate how the change will impact you. Please let me know, now's the time to convince me to change some of the details ;-)

Here's a full list of changes in this snapshot:

  • Changed class loader architecture to represent each .NET assembly with its own class loader.
  • Changed system class loader to the application entry assembly class loader (except if the java.class.path system property is explicitly set, then you get a URL class loader that loads from the specified class path).
  • Ported stub class generator from C# to Java and incorporated it into IKVM.GNU.Classpath.dll.
  • Hooked up assembly class loader resource loading with stub generator, to support loading .class stub files for .NET and statically compiled classes.
  • Changed ikvmstub to create stub classes by simply loading them as resources.
  • Removed IKVM.Runtime.Util methods that existed for ikvmstub.
  • Fixed runtime/ikvmc to no longer depend on the CLR interning string literals.
  • Runtime no longer locks the class loader instance before calling loadClass.
  • Removed old mono bug work arounds from jni code.
  • Class.getProtectionDomain() now returns a more meaningful ProtectionDomain (including a CodeSource) for statically compiled Java code and .NET assemblies.
  • Moved VMSystem.setIn/setOut/setErr implementation from C# to Java.
  • Changed the way final instance fields are handled (added a private setter method to the property) to remove the need for the runtime to correlate the field with the property.
  • Fixed final field property accessor generator to make sure that the generated method name doesn't clash with other methods.
  • Moved IKVM.Runtime public API to IKVM.GNU.Classpath (and renamed to namespace and method names to follow Java naming convention).
  • Set system property to disable usage of Graphics 2D by Swing implementation.
  • Added java.vendor.url.bug, java.runtime.name and java.runtime.version system properties.

Source is in cvs. Binaries can be downloaded here: ikvmbin-0.31.2421.zip

Friday, 18 August 2006 11:09:00 (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]
Friday, 18 August 2006 15:23:26 (W. Europe Daylight Time, UTC+02:00)
The only "issue" I can see is that the handling of resources dynamically loaded from java-land is different, and more restrictive (but perhaps more appropriate?).

This is related to a query I made on the list a few days ago about making resources available to java code via Class.getResource(). With ikvm <= 0.30, resources placed in the same directory as one's application were available through Class.getResource(). Now, those seem to be unavailable, which makes sense given the classloader mods.

It's no biggie -- I don't mind having to specify resource paths via "ikvm:"-prefixed appsettings (http://www.nabble.com/System-Properties-through-IKVMC-dlls-t2017210.html). However, I would suggest the following as nice-to-have features:

- providing some way to modify java system properties at runtime (any modifications I attempt now via System.setProperty() doesn't seem to be visible to java code)
- providing some way to "register" resources at runtime, which *would* then be available to Class.getResource() et al.

Now that I think of it, the second mechanism might actually violate the security policy of a typical classloader. Hey, I'm an ideas guy! :-)
Friday, 01 September 2006 01:05:50 (W. Europe Daylight Time, UTC+02:00)
The .31 version breaks my application that is statically compiled. It performs class generation/loading at runtime. Under .31, the classloading fails (work fine for versions < .31). I'm not suggesting that the .31 classloading model is bad, but I think it will break a lot of java code that relies on semi-standard classloader semantics. Perhaps the class loader model could be configurable? One fundamental difference I see between OSGI and a classloader-per-assembly model is that in .Net there is
not really a 100% analog of the jar manifest (as far as I know). If you build an exe with csc and refer to other assemblies via -reference, csc will remove them from the reference section of the final assembly if there are not any explicit references to it in the code being compiled. If you were building a bundle under OSGI, this removal would not
occur. This is only a problem for the dynamic loading of classes, but that is a very common thing to do in java. Fundamentally OSGI provides a classloader per module/plugin where a module may be several libraries.

Todd Stout
Saturday, 06 January 2007 04:02:32 (W. Europe Standard Time, UTC+01:00)
A per assembly classloader does not work unless you navigate through the assembly hierarchy until you reach the executable.

The following scenario will demostrate that the current approach is broken:
a.exe --> b.dll --> c.dll

The C assembly has a convenience method for loading classes. Assembly B call this convenience method passing in the name of a class inside assembly B.

Since the physical Class.forName call now occurs from the C assembly it will now get the C assembly classloader and the class in the B assembly cannot be found even though assembly B has been loaded.

Another example that will fail is to dynamically load a class from the System assemblies.

So the current implementation of just taking the calling assembly (C in this example) to determine which classloader to use will fail. You will have to navigate the assembly calling hiearchy in order to make this work.

Johan Majoor
Friday, 09 February 2007 23:45:02 (W. Europe Standard Time, UTC+01:00)
An example that argues for Johan's point:
a.dll and b.dll contains junit test cases and were compiled referencing junit.

Now if I compile junit alone into junit.exe (with the text running as the main class), I get a ClassNotFoundException when running junit.exe given a test case in either a.dll or b.dll.

Thus I will have to separately compile both a.dll and b.dll with junit in them. This is definitely not ideal.
Peilin Zhang
Sunday, 08 July 2007 23:58:09 (W. Europe Daylight Time, UTC+02:00)
This seems to break Class.forName for some of my applications.

I use the Mozilla Rhino javascript libraries. Rhino uses Class.forName quite a lot. Rhino has been compiled into a .NET assembly and I access native .NET types from javascript interpreted by Rhino.

I can use Class.forName('my.type') to load a class in a custom assembly from my Main() method perfectly fine but the same call (Class.forName('my.type')) from javascript doesn't work. The only classes that seem to be loadable by Class.forName after Rhino initializes are the ones from mscorlib and the java classes.

I've forgotten a lot about how ClassLoaders in Java works so I'm not quite sure what's happening but this change seems to cause issues in post 0.30 builds (up to the current 0.34) which didn't occur before.
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