Call .NET code from Jython

Suppose you needed to call .NET code from a Python application. You could use IronPython or Python for .NET, both of which are implemented in .NET, and have the built-in ability to access .NET binaries from Python code. But what if your Python application needed to access both Java and .NET binaries (so that you’d need cross-platform capabilities regardless of whether you used a .NET-based or Java-based Python)? Alternatively, what if you were required to use Jython or maintaining a legacy Jython application and had to add .NET functionality? In these latter cases, JNBridgePro can solve the problem. In this post, we’ll show how easy it is to write a Jython program that accesses .NET classes (and accesses Java classes, too).

Let’s start with a simple .NET library (here written in C#, although it could just as easily be written in F# or VB.NET or any other .NET language):

using System;

namespace DotNetLibrary
{
     public class HelloWorldFromDotNet
     {
          private string theString = "";

          public HelloWorldFromDotNet()
          {
               theString = "Hello World from .NET!";
          }

          public HelloWorldFromDotNet(string s)
          {
               theString = s;
          }

          public string returnString()
          {
               return theString;
          }
     }
}

Next, build the .NET project and proxy the class DotNetLibrary.HelloWorldFromDotNet (and supporting classes), and create a proxy jar file.

We then create a new Jython application (we used PyDev for Eclipse, but you can use your favorite Python environment or just use a text editor and a console window), and make sure that the proxy jar file, jnbcore.jar, and bcel-5.1-jnbridge.jar are all in the classpath.

Now, let’s write a simple Python application that instantiates the HelloWorldForDotNet class and exercises the API:

import com.jnbridge.jnbcore
import DotNetLibrary
import java.util

props = java.util.Properties();
props.setProperty("dotNetSide.serverType", "sharedMem")
props.setProperty("dotNetSide.assemblyList.1", "C:/Jython Example/DotNetLibrary.dll")
props.setProperty("dotNetSide.javaEntry", "C:/Program Files (x86)/JNBridge/JNBridgePro v7.2/4.0-targeted")
props.setProperty("dotNetSide.appBase", "C:/Program Files (x86)/JNBridge/JNBridgePro v7.2/4.0-targeted")

com.jnbridge.jnbcore.DotNetSide.init(props)

h = DotNetLibrary.HelloWorldFromDotNet()
print h.returnString()

h = DotNetLibrary.HelloWorldFromDotNet("Test String from DotNet")
print h.returnString()

There are a couple of significant things to note here. First, notice that the application calls both Java classes (java.util.Properties and com.jnbridge.jnbcore.DotNetSide) and .NET classes (DotNetLibrary.HelloWorldFromDotNet).

Second, and this is very important, note that we’re using “package” import statements (i.e., import DotNetLibrary), rather than from-import statements (i.e., from DotNetLibrary import HelloWorldFromDotNet). The reason for this is that using the from-import statement will cause the target Java class to be loaded, which will cause any static initializers to be executed. In the case of any proxy classes, this will cause an exception to be thrown because proxy code (in this case, a static initializer) is executed before the call to DotNetSide.init() is executed. Using the package import statement does not cause any classes to be loaded. However, using the package import statement means that any references to proxies or Java classes need to use the fully qualified names.

(As an aside, although the problem of thrown exceptions only occurs when proxy classes are imported, we recommend using Jython’s package import statement in all cases, since it works exactly the same way as the Java import statement, in that it only functions at compile time as a mechanism for resolving names. The Jython from-import statement, on the other hand, introduces runtime behavior that is not present in the Java import statement, and that can lead to surprises.)

Finally, we need to configure JNBridgePro. In our example, we’ve configured JNBridgePro to use shared memory, and have generated the configuration information at run time. Alternatively, we can configure JNBridgePro through a configuration file, by modifying the call to DotNetSide.init() as follows:

com.jnbridge.jnbcore.DotNetSide.init("C:\\Jython Example\\jnbcore_sharedmem.properties")

Once everything is set up, we can run the Jython program, and we’ll get the following output:


Hello World from .NET!
Test String from DotNet

That’s all there is to it! We’ve shown how you can use JNBridgePro to write a Python (actually, Jython) program that can call both Java and .NET code. In a future post, we’ll turn things around and show how to use JNBridgePro and a .NET-based Python to call Java code.

Do you plan to use JNBridgePro to make cross-platform calls from Python programs? If so, please let us know.