An Introduction to IKVMIn 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.
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 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 |
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
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.
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.
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
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.