BT

Fighting Developer Fatigue with JNBridge

| Posted by Wayne Citrin on Oct 01, 2015. Estimated reading time: 8 minutes |

Developer fatigue is the overwhelming frustration felt by developers who are under pressure to keep current with a flood of new languages, libraries, frameworks, platforms and programming models. It’s not an abstract concept. In fact, well-regarded analysts and developers like Stephen O’Grady, Tim Bray and Marco Arment have all weighed in on the developer fatigue phenomenon.

JNBridge’s JNBridgePro emerges as a practical, efficient and simple way to help alleviate developer fatigue by supporting interoperability between languages like Python, Groovy and Clojure, as well as Java and .NET code.

For example, let’s say you’re learning Python and want to start using it in projects —or perhaps you’ve been told to start using Python. Possibly you’ve already invested a lot of time and effort in developing .NET-based libraries with lots of specialized business logic. Jumping into Python with both feet and reimplementing everything in the existing .NET libraries would involve learning an overwhelming amount of new material and contribute to developer fatigue and potential burnout.

A better approach would be to keep as much of the .NET-based technology as possible, and start by nibbling around the margins, creating framework code in Python, and calling the more substantial .NET-based logic where needed. Later, more Python skills can be acquired and more Python code can be added, as necessary, and functionality can be migrated out of the .NET libraries if that’s what’s desired. This “go slow” approach can mitigate developer fatigue and allow you to avoid prematurely committing to new technologies that may turn out to be insufficiently robust for production use, or may soon be supplanted by even newer technologies. Note the approach described here can be used to continue using both legacy .NET and Java binaries with emerging languages.

Once you’ve decided on this approach, there are a couple of ways to proceed. You can choose a .NET-based Python implementation like Iron Python, but you might have questions about its long-term support, since it has been abandoned by Microsoft and is currently being maintained by volunteers. Alternatively, you can use Jython, a Java-based Python implementation, and use JNBridgePro, the Java-.NET interoperability tool from JNBridge, to bridge from Jython to .NET. Jython is implemented in Java and can call Java binaries. Since JNBridgePro supports calls from Java to .NET by generating Java-based proxies for .NET classes, methods, etc., calling the Java-based proxies amounts to calling the underlying .NET code.

As an example, let’s assume we have a simple .NET library, here written in C#:

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;
}
}
}

From the .NET DLL implementing the above code, we first use JNBridgePro to generate a Java JAR file containing the proxied versions of the HelloWorldFromDotNet class and its constructors and methods. We then create a Jython project, and include in the classpath the proxy JAR file and other JNBridgePro runtime components. Once we’ve done that, we can write a Python application that calls the proxies (and, by extension, the underlying .NET code). Here is a simple Python application that instantiates the HelloWorldFromDotNet 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()

It’s worth noting a couple of things here. First, the application calls both Java classes (java.util.Properties and com.jnbridge.jnbcore.DotNetSide) and .NET classes (DotNetLibrary.HelloWorldFromDotNet). Second, the calls to props.setProperty() and DotNetSide.init() are JNBridgePro boilerplate, used to configure and then start up JNBridgePro. The actual calls from Python to .NET are in the lines following the call to DotNetSide.init().

Once everything is set up, running the Python program yields the following output, all of which is generated from the .NET code:

Hello World from .NET!
Test String from DotNet

A similar approach can be used with many languages, and allows you to ease into a new language while retaining as much of your original investment as possible. It can be used whether you have Java or .NET code. We’ve prepared examples for a number of languages, including Python, Groovy and Clojure, that you can find on our website. We plan to release more examples for additional languages.

However, if you have a new language you’d like to start developing in while continuing to use existing .NET or Java code, you can do so even if we haven’t prepared an example for you. Just use the following simple guidelines.

The “new” language must have an implementation on the Java or .NET platforms. Since JNBridgePro bridges between Java and .NET (or, more precisely, between the Java Runtime and the .NET Common Language Runtime or CLR), the new language must be implemented on one of these platforms.

If you want to call from the new language to your Java or .NET code, the “new” language must allow for calls to other binaries that run on the same platform. If the language has been implemented on the Java platform (like Jython or Clojure) it must have a mechanism for calling other Java binaries. If programs in this language can call Java classes, then they can call proxied .NET classes generated by JNBridgePro, thereby supporting cross-platform calls. Similarly, if a .NET-based language (such as Iron Python) can call other .NET assemblies, then it can call proxied Java classes. In either case, just call the proxied classes and methods in the same way as you would call the Java or .NET classes the language/environment was designed to support calling.

If you want to call from your Java or .NET code to code written in the new language, the new language, when compiled, must expose an API that can be proxied and called. This is a little trickier. If the new language compiles to object-oriented Java or .NET binaries, then proxying those APIs should be trivial. However, if the new language runs in its own runtime (albeit .NET- or Java-based), then a different approach is necessary. Generally, such languages provide a .NET- or Java-based invocation API that allows outside callers to access the runtime and invoke specified methods. If such an API exists, you can simply proxy it, and use it to invoke the desired methods cross-platform.

For example, if you want to call a Groovy method myMethod from Groovy file myFile.groovy from .NET, you can proxy the Java-based Groovy runtime class groovy.lang.GroovyShell and java.io.File (along with supporting classes). Once that’s done, you can write the following C# code to call the method:

using groovy.lang;
using java.io;
…
new GroovyShell().parse(new File("MyFile.groovy")).invokeMethod("myMethod", args);

Similar APIs exist for calling Clojure and Jython from Java, and can be proxied and used from .NET.

In some cases the language in question may not offer an obvious invocation API. A number of years ago, we had a customer who wanted to call Fujitsu NetCOBOL code (admittedly not a “new” or “emerging” language) from Java. The compiled DLLs exposed an API that looked like gibberish. In such cases, look for instructions on calling the language in question from other .NET languages. If the API used is a managed interface, it can be proxied and called cross-platform.

Make sure you configure JNBridgePro before you make the first proxy call. Once you’ve determined your proxying strategy, and have included proxy calls in your application, you’ll need to make sure JNBridgePro has been properly configured. JNBridgePro provides configuration APIs: In the Python example above, the calls to props.setProperty() and DotNetSide.init() perform the configuration. For .NET-to-Java, JNBridgePro provides an equivalent API.

Beware of implicit static initialization. In some languages, explicitly referencing a class can cause the class to be loaded and its static initializers to be executed. This can lead to problems, particularly if the class being loaded and initialized is a proxy class, and the JNBridgePro configuration code has not yet been executed. In such cases, you must figure out a way to reference a class in the language without actually loading it. For example, like Java, Jython allows you to import a specific class name or a package name (that is, it imports the names of all the classes in the package). However, unlike Java, where the import statement simply makes names visible, the Jython class name import statement (from-import) actually loads the class and executes its static initializers. This presents a problem when the class is a proxy class; its initializer will be executed at the very beginning of the code, before the configuration code can execute. The problem can be avoided by using package import statements, which don’t cause classes to be loaded, and that’s what we do in the Jython example here. In any case, you’ll need to make sure no proxy class is statically initialized before the JNBridgePro configuration is performed or errors may occur.

There are lots of new languages out there, and keeping up with them can be overwhelming. However, you can take advantage of the fact that many are based on the .NET and Java platforms, and ease into any such new language by learning smaller pieces of the new languages, writing smaller applications to start, and leaving most of the functionality in existing .NET or Java code you’re already familiar with.

Using the framework and guidelines we’ve provided, you can approach any novel interoperability scenario involving a new JVM- or CLR-based language. At the same time, developer fatigue will effectively be avoided (or at least alleviated) and achieving your objectives will come at a much lower emotional and financial cost.

About the Author

Dr. Wayne Citrin is CTO and cofounder of JNBridge, LLC, the leading provider of interoperability tools to connect Java and .NET frameworks.

Rate this Article

Relevance
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread
Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Discuss
BT