Bridging .NET and Java

Create hybrid apps that let your Java programs call native .NET code.

When it comes to integrating .NET and Java code infrastructures, developers working with .NET Framework 3.0 can turn to Windows Communication Foundation (WCF) and service-oriented architecture (SOA) to bridge the gap.

WCF lets developers expose a managed .NET assembly as a Web service, and supports open standards such as WSDL and SOAP for interoperating with non-.NET Web services platforms.

However, there are cases where interoperating with .NET-based Web services can prove to be exceedingly difficult because of limitations in Java APIs or because of the proprietary nature of some of the bindings used in WCF.

There is a solution to this problem, where we can have Java integrate with .NET natively. Let's say that your team has spent the last six months writing a significant amount of .NET code. Then they're given the requirement that it must be accessible by Java. The following hello example shows how such integration can be done. This example applies to Sun's Java SE Development Kit (JDK) version 1.4 or later and Visual Studio 2005 and 2008.

Let's first look at the .NET code, HelloExample.cs:

public class HelloExample {
	public void sayHello() {
		System.Console.WriteLine(hello from c#);
	}
}

Now let's look at a simple Java application that we want to invoke this C# method: HelloExample.java:
public class HelloExample {
private native void sayHello();
static {
	System.loadLibrary(HelloExample);
	}
	public static void main(String[] args) {
		new HelloExample().sayHello();
	}
}
The loadLibrary call tells the Java Virtual Machine (JVM) to load HelloExample.dll, which I'll describe later, and which acts as a bridge between the Java and .NET code. The sayHello method, identified by the native keyword, is used to call a function in this DLL that will delegate the sayHello method in the C# class. This approach uses Java Native Interface (JNI), which can be thought of as being similar to .NET's Platform Invoke (P/Invoke) feature. Now let's take a look at the source code for HelloExample.dll, which is the glue between our Java and .NET classes. Here's HelloExample.cpp:

#include HelloExample.h
#using HelloExample.net
module
#using <mscorlib.dll>
using namespace System;
JNIEXPORT void JNICALL Java_HelloExample_sayHello(JNIEnv *, jobject) {
	HelloExample^ he = gcnew HelloExample();
	he->sayHello();
}
This is managed C++ code that uses a JNI interface so that it can be accessed by HelloExample.java. The method signature and header file were generated automatically from HelloExample.java using the javah command included with the JDK. The HelloExample.ne tmodule file contains the compiled code for the HelloExample C# class that's being called in the body of the Java_Hello Example_sayHello function.

Results
If you were successful in building your code, you're left with a Java application that prints hello from c#. When this application is run, a JVM is started and is told to run the Java HelloWorld class. Next, HelloExample.dll is loaded using Java's System.loadLibrary method. When this DLL is loaded, so is the .NET Common Language Runtime (CLR). Finally, the Java class calls the native sayHello method -- the Java_HelloExample_sayHello function -- which at last delegates to the sayHello method in the C# class.

Parting Shots
At this point you may be wondering if we can do this the other way around -- having your .NET app call Java code. This could be used to solve the opposite kind of problem, where you've written a significant amount of Java code and now need to expose it to .NET. This type of integration can also solve the problem of allowing your .NET application to access Java APIs. Fortunately, this is possible and the integration process is similar. You'd have your .NET code use P/Invoke to call a function in a Win32 DLL. This Win32 DLL would then use JNI to create a JVM and then use that virtual machine to call the desired methods in your Java class.

Regardless of the integration target, you can expect challenges in a complicated, real-world project. One problem is type conversion, as you must covert JNI types to .NET types and vice versa. Another problem is exception handling, as you'll likely need to be able to have your .NET exceptions handled by Java and vice versa.

Once you've managed to build your hybrid application, a few additional issues remain. First, your application depends on both the .NET CLR and Java Runtime Environment (JRE), which may or may not be present on client systems. You may need to plan to ship the installer for .NET and Sun's JRE with your product. Second, your applications will have two heaps, one managed by the .NET CLR and one by a JVM. Both heaps are competing for memory, and if one uses too much the other will start throwing out-of-memory exceptions. This can usually be solved by limiting the amount of memory available to one or both of the heaps -- by passing an 'Xmx' argument for your JVM, for example.

These are important considerations, but easy to manage if you plan ahead.

About the Author

Joseph Benken is a software engineer for Parasoft Corp.