ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


An Introduction to IKVM An Introduction to IKVM

by Avik Sengupta
08/18/2004

In a nutshell, IKVM can be described as a Java Virtual Machine for the .NET CLR. But that brief statement hides a whole new world -- IKVM is the first serious option for in-process Java-to-.NET interoperability. Developed primarily by Jeroen Frijters and a small team of contributors, IKVM is an amazing new technology that conclusively breaks down the barriers between Java and .NET. So if you are creating a .NET application, but want to use that cool new Java library that doesn't yet have a .NET counterpart, here's a solution for you. Conversely, if you are a Java developer who wants to call a .NET library from Java, IKVM is what you need.

Installation

IKVM requires a .NET runtime to be available on your system. If you are on a Windows operating system, you should have the Microsoft .NET Framework installed. If you are on Linux (or Solaris or OS X), you should have Mono (preferably version 1.0) installed.

Since the IKVM binary distribution consists primarily of .NET assemblies, installing is simple. Just download the binary .zip from the web site, and unzip its content into a directory. Linux users also have the option of downloading a packaged version of IKVM bundled with the Mono 1.0 distribution.

To develop applications with IKVM, you should also have a Java compiler installed. You can use any compiler that produces standard bytecodes, such as Jikes or or the Sun JDK (javac). In Windows, you may wish to install the IKVM .dlls into the Global Assembly Cache to make development easier.

IKVM Components

IKVM essentially consists of a compiler that can transform Java bytecodes into .NET IL representation, either statically or dynamically. It includes the Java standard libraries, in the form of a version of GNU Classpath, pre-compiled into .NET. It also includes JNI providers for Mono and Windows, to enable Java code to access native (C/C++) libraries.

Related Reading

Mono: A Developer's Notebook
By Edd Dumbill, Niel Bornstein

All of the above boils down to three major modes of operation. First is the application ikvm, which can be used as a drop-in replacement for any other JVM. When run in this mode, the Java bytecodes are compiled to .NET IL at runtime, and hence, is known as the dynamic mode of operation.

Second is the ikvmc command, which can be used to convert Java bytecodes into .NET IL. Thus, you can convert a set of Java class files into a .NET assembly.

Since this manner of use statically compiles the Java bytecodes, it's known as the static mode. Note that while the dynamic mode fully supports the Java classloader semantics, in the static mode, there are necessarily some limitations. Among the issues to watch out for is the fact that all classes are loaded by the bootstrap classloader. See the threads for the gory details. In brief, many Java programs assume this.class.getClassLoader() will return non-null. That, however, is not a valid assumption for classes loaded by the bootstrap loader.

Also, while classloader functionality (such as Class.forName(..)) is available to use, and indeed can be used to load either statically compiled classes or Java bytecode, remember that loading classes out of .NET assemblies that are not referenced directly or indirectly from your application may not work without manual intervention. See the documentation for more detail on this and other hairy issues that arise when two different worlds collide!

The third and final component of IKVM is the ikvmstub compiler, which can be used to generate stubs in Java that wrap .NET classes. With this, you can write Java code that calls into .NET libraries. Note however, that the compiled Java code has to be run on the IKVM JVM. This feature, when coupled with the ikvmc command, makes Java a first-class language to develop applications targeting the .NET CLR

Usage

Let us illustrate all of this with a real-life example. XSL:FO is a W3C recommendation that describes the formatting and flow semantics for paginated presentation in an XML syntax. It is widely used for creating structured source documents for eventual transformation into printed materials. Read "What is XSL-FO?" by G. Ken Holman for an accessible introduction to this technology.

Apache FOP is an open source Java library that can convert xsl:fo files into .pdf format. It was one of the first xsl:fo processors available, and thus over the years has grown into a feature-rich and stable application. As a .NET developer, however, you would have bemoaned the lack of a quality open source FO processor that you could use. This is exactly where IKVM comes in.

To get FOP, you can either build from CVS (get the fop-0_20_2-maintain branch) or download the binary distribution and unzip the package into any directory. For our example, we will use the the normal.fo sample that is included in FOP. To create a .pdf from the xsl:fo file, we would normally use a command such as:

java -cp build/fop.jar:lib/xml-apis.jar:
    lib/xercesImpl-2.2.1.jar:
    lib/avalon-framework-cvs-20020806.jar:
    lib/batik.jar 
    org.apache.fop.apps.Fop -fo normal.fo 
         -pdf normal.pdf

Note: All of the commands displayed in this article have been broken up to fit a narrow web page, but need to be typed together on one line. All code and commands in this article were written and run on a Linux OS using Mono. To use in Windows, simply change the path and file-separation characters. Also note that you do not need to provide references to assemblies installed in the GAC; the framework will automatically search and resolve such references.

In exactly the same way, we can use IKVM to run FOP via dynamically compiling Java bytecodes to .NET IL:

ikvm -cp build/fop.jar:lib/xml-apis.jar:
    lib/xercesImpl-2.2.1.jar:
    lib/avalon-framework-cvs-20020806.jar:
    lib/batik.jar 
    org.apache.fop.apps.Fop -fo normal.fo 
         -pdf normal.pdf

And that's it! You have successfully run a Java program -- a reasonably complex program, for which no .NET equivalent exists -- within the .NET Framework. However, this is not all. You can now make calls to FOP methods from within a C# program!

First you need to compile the FOP .jar and its dependencies into .NET assemblies. Note that you do not necessarily need to compile all dependencies; IKVM will happily mix .NET and Java by loading some classes from Java bytecodes at runtime.

ikvmc -target:library 
     -reference:/usr/lib/IKVM.GNU.Classpath.dll 
     lib/xml-apis.jar
     
ikvmc -target:library
     -reference:/usr/lib/IKVM.GNU.Classpath.dll 
     -reference:xml-apis.dll 
     lib/xercesImpl-2.2.1.jar
     
ikvmc -target:library
    -reference:/usr/lib/IKVM.GNU.Classpath.dll 
    -reference:xml-apis.dll 
    lib/avalon-framework-cvs-20020806.jar
    
ikvmc -target:library
    -reference:/usr/lib/IKVM.GNU.Classpath.dll 
    -reference:xml-apis.dll 
    lib/batik.jar
    
ikvmc -target:library 
   -reference:/usr/lib/IKVM.GNU.Classpath.dll 
   -reference:xml-apis.dll -reference:batik.dll  
   build/fop.jar

This will give you the following .NET assemblies in your current directory:

avalon-framework-cvs-20020806.dll  batik.dll
fop.dll  xercesImpl-2.2.1.dll  xml-apis.dll

Now load up your favorite IDE (for example, VisualStudio in Windows or MonoDevelop on Linux), and add references to these .dlls in your project. And voilą! Your favorite Java project is ready to be used from within .NET programs. For example, the following simple code in C# is used to call FOP's Driver class to transform an xsl:fo file into a .pdf file:

// Main.cs
using System;
using org.apache.fop.apps;
using ikvm.lang;

class MainClass
{
   public static void Main(string[] args)
   {
    //Load assemblies that are not directly
    //referenced since no CLASSPATH is defined
     AppDomain.CurrentDomain.Load("xercesImpl-2.2.1");
     AppDomain.CurrentDomain.Load("batik");
     java.lang.System.setProperty(
       "javax.xml.parsers.SAXParserFactory",
       "org.apache.xerces.jaxp.SAXParserFactoryImpl");

   
     java.io.FileOutputStream fs = new
          java.io.FileOutputStream("normal.pdf");
     org.xml.sax.InputSource isrc = new 
          org.xml.sax.InputSource("normal.fo");
     Driver driver = new Driver(isrc, fs);
     driver.setRenderer(Driver.RENDER_PDF);
     driver.run();
   }
}

If you have downloaded a binary of FOP 0.20.5, you will need a patched version of fop.jar to successfully run the above code. This is fixed in later CVS versions. The patch is for the bootstrap classloader problem mentioned earlier.

This gives a flavor of what can be done with IKVM. There is, of course, a lot of technology that goes under to covers to achieve this, but that is a topic large enough for another article.

Status

The JVM implementation of IKVM is reasonably complete. It has, for example, full support for reflection, as well as JNI. However, it is well known that to ship a JVM, the most effort has to go into the implementation of the standard libraries. In this regard, IKVM leverages the GNU Classpath project, and therefore has as much support for the standard libraries as GNU Classpath. Thus, IKVM today can run many complex server-side Java libraries. The weak point is the GUI capabilities, not only for the immature (though rapidly improving) implementation of AWT and Swing in GNU Classpath, but also the fact that the AWT peers need to be natively implemented in IKVM. This is where the project is most in need of contributions.

Conclusion

IKVM breaks down the barriers between Java and .NET, probably two of the most significant language platforms of the day. In the sometimes adversarial atmosphere between the two communities, this can be viewed with concern by many Java developers, since the barrier of interoperability against a large installed library base is not longer sufficient to protect your skills. However, one can also see it as an opportunity, increasing the range of target platforms on which the Java programmer may utilize his skills. I think IKVM eventually makes language bigotry the loser, and the winner is that old cliché -- "the right tool for the job."

Avik Sengupta is the CTO at Itellix Software Solutions and a contributor to the Jakarta POI project.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.