Saturday, October 31, 2009

How calling from .NET to Java works in jni4net

In this article I would like to explain how calling from .NET to Java works with jni4net.

First of all you should know that Java Virtual Machine (JVM) is exposing Java Native Interface (JNI). It is native/binary interface which allows other programs to control JVM: load classes, create instances and run methods. It as well allows you to control object lifetime by holding handle to instance. Usual way how to consume JNI interface is to use %JDK%\include\jni.h in your C++ program and then load jvm.DLL. I wanted solution for .NET, so I use [DllImport] attribute and I translated the header file from C to C#. I also converted all pointers and handles to IntPtr. So now we have JNI interface accessible to any .NET code.

Now it's quite easy to use JNI methods to call Java objects, but it's far from convenient. So the next step was to use Java reflection and get signatures of core objects and generate proxies. The proxies look like Java classes, they have same name, namespace, same methods with same signatures. But it don't have the implementation in .NET but rather they call the real implementation in JVM using JNI. The reflection and proxy code generator is reusable idea, so I created 'proxygen', it's tool which is part of jni4net package. You could use it to wrap your own classes.
jni4net JVMProxy

Now you should know few tricks. JNI calls are done on handle of the method, which could be retrieved by method name and signature. See javap. To make it faster, I pre-bind the proxy-class to real-JVM-class during start-up.

To make the proxy good citizen in .NET world, java.lang.Object overrides Equals(), GetHashCode(), ToString() .NET methods and forward the calls to appropriate Java equivalent. You should be aware that there could be multiple proxies for same Java instance. java.lang.String proxy implements implicit conversion to CLR String.

Because we need garbage collection work, proxy implements finalizer. When CLR garbage collector finds lonely proxy, we release JNI handle of the real Java instance, so it could be collected on JVM side as well. Warning, it is possible to create cycle between objects across both heaps, which would prevent GC from collection. I have no good solution for that now, just be careful.

Another feature to mention is exceptions. To make Java exceptions useful in CLR, they should be inherited from System.Exception. Simply to be able to throw and catch them in .NET. But it means that they could now be inherited from java.lang.Object proxy. This is compromise, but it's worth of it, because now you could catch exceptions thrown by Java method in .NET code because jni4net does transparent translation for you. You will receive proxy of exception. To overcome the problem with common base class, I introduced java_.lang.IObject interface with all expected methods.

Last note would be about call marshalling. It's done with PInvoke on CLR side and with JNI on JVM side. The primitive types are very well compatible. Unsigned types from CLR are transmitted binary. Strings are translated as Unicode, it's bit slow. Any other non-primitive parameter is Java object. Which means you need to pass another proxy/Java object as parameter (for brevity we ignore interfaces now). When returning from the call, we could have return value. It is the way how to send Java instances back to .NET. jni4net/proxy wraps the JNI handle for you. It finds best-fit proxy-class and returns its instance. The proxy contains JNI handle to the real Java instance.

Next time about calling back from JVM to .NET and proxies of CLR objects in Java.

Saturday, October 10, 2009

jni4net - bridge JVM and CLR

I'm proud to present first public release of jni4net - Object oriented, fast, intraprocess bridge between JVM and CLR.

Hello World!

From C# to Java
using net.sf.jni4net;
public class Program
    private static void Main()
        Bridge.CreateJVM(new BridgeSetup());
        java.lang.System.@out.println("Greetings from C# to Java world!");
This is very basic demonstration of the principle, full version of this sample and another 3 sample applications could be found in binary distribution. The others are same Hello World but from Java to .NET, usage of Apache FOP from C# for xsl:fo and last is creation of WinForms dialog from Java.

Please download here and talk back.

Next time I will write about why I created it, how it works, what are the features and what are the next steps. Watch this space.

Friday, October 9, 2009

Export native 64bit method from .NET assembly

It is well known fact that .NET assembly could be tweaked to export native method, similar way how normal DLLs do it. There is good description and tool from Selvin for 32bit native function.
My problem was how to do it for 64bits. Here you go.

1) you IlDAsm your assembly into il code.
2) Edit the IL and change header to look like this
for 32bit
.corflags 0x00000002
.vtfixup [1] int32 fromunmanaged at VT_01
.data VT_01 = int32[1]
for 64bit
.corflags 0x00000008 
.vtfixup [1] int64 fromunmanaged at VT_01
.data VT_01 = int64[1]
3) Header of your exported method would look similar to this. This is same for 32bit version.
.vtentry 1 : 1
.export [1] as Java_net_sf_jni4net_Bridge_initDotNet
4) You IlAsm the file back into DLL. For x64 you use /x64 flag.

Hack ReSharper for x64 unit tests

If you need to develop 64bit .NET application and run unit tests with R#, you will find that it's not possible, because Visual Studio is 32bit process and R# task runner is loaded as 32bit as well. There is quick and dirty solution to that.

1) Stop Visual Studio
2) Find JetBrains.ReSharper.TaskRunner.exe
3) Drop read-only flag on the file
4) Run
CorFlags.exe JetBrains.ReSharper.TaskRunner.exe /32BIT- /Force

The assembly have now broken signature and VS/R# complains about that. But now you could debug your 64bit unit tests. More info would be probably here