Lead Image © Ivan Mikhaylov, 123RF.com

Lead Image © Ivan Mikhaylov, 123RF.com

Blending Java with other programming languages

It's in the Blend

Article from ADMIN 26/2015
By
Java is not just about beans, it's also about the huge variety of libraries and frameworks that keep the language alive. If you feel like a bit of blending, Java integrates many flavors of third-party languages.

Neither project managers nor programmers mix languages purely for pleasure. The former are worried about the complexity and the increased demands on their team, while the latter prefer to use things that they feel most comfortable with – and that is precisely one programming language for most of them. Having said this, the second programming language often does more good than harm in a software project:

  • Bazaar method: The more expensive the software, the more benefits you have from leveraging tried and trusted routines – even if the recycled code is written in a different language.
  • Performance: If you need low-level access to hardware and operating system resources, low-level programming languages offer superior performance.
  • Scripting: Scripts and scripting languages give power users powerful tools. This is still the case with complex enterprise applications based on J2EE.
  • Integration capability: Java applications can act as one component in the greater context and may need to adapt to match the look and feel of a desktop.

Java is a very powerful language, so it comes as no surprise that it also supports integration of software written in third-party languages for any use case. The following sections look into these techniques, along with their benefits and drawbacks.

Nothing Works Without C

One reason for Java's success is that it protects the developers from a few tricky things that were required in C and C++, in particular dynamic memory management. Despite this, the makers of Java saw from the outset that Java would have difficulty surviving in the real world without being able to access the versatile resources of existing C libraries. Thus, even the very first Java version offered the option of integrating C code in the form of the Java Native Interface (JNI).

Java access to C relies on two layers (Figure 1). At the top is a lean Java class, which does little more than describe the interface and load the next layer by means of a static method. From a technology point of view, the second layer is a dynamic library (.so file, or a DLL on Windows) that converts Java calls to C.

Figure 1: Java accesses C code via layers.

Here is a practical example: In one of my projects [1], the task was to make the Readline library available in Java. Native Java programs cannot pick up output from stdout. In contrast, Readline can output a line in which the user can navigate with keystrokes and also edit in a style similar to Bash (Figure 2).

Figure 2: Thanks to Readline, the input from the previous command can be easily edited.

The library is used, for example, in Jython [2]; Jython implements the Python language in Java. Listing 1 shows part of the class definition. For design reasons, all of the native methods are private; in other words, there is a private native String readineImpl() (line 34) for the public String readline() method (line 17). The special thing about this class is that it is not abstract; however, it still only defines one interface for these native methods. The load() (lines 10-13) loads the native library.

Listing 1

Snippet of the Readline.java Class

01 package org.gnu.readline;
02
03 import java.io.*;
04 import java.util.*;
05
06 public class Readline {
07
08 [...]
09
10   public static final void load(ReadlineLibrary lib) throws UnsatisfiedLinkError {
11     [...]
12     System.loadLibrary(lib.getName()); // might throw UnsatisfiedLinkError
13   }
14
15   [...]
16
17   public static String readline(String prompt, boolean addToHist)
18    throws EOFException, IOException, UnsupportedEncodingException {
19     [...]
20     String line = readlineImpl(prompt);
21     if ((line != null) && (addToHist)) {
22       addToHistory(line);
23     }
24     return line;
25   }
26
27   public static void addToHistory(String line) {
28     [...]
29     addToHistoryImpl(line);
30   }
31
32   [...]
33
34   private native static String readlineImpl(String prompt)
35    throws EOFException, UnsupportedEncodingException;
36
37   private native static void addToHistoryImpl(String line);
38   [...]
39 }

The javah tool provided by the JDK generates the C header file, org_gnu_readline_Readline.h, from the bytecode of the class:

javah -classpath $(BUILDDIR) -jni org.gnu.readline.Readline

Listing 2 shows a snippet of this. The actual implementation then involves converting the Java types passed in – such as jstring to char* – into a format that the C library understands. There are a couple of pitfalls here, especially on non-Unicode systems.

Listing 2

Snippet of the C Header Generated

01 /* DO NOT EDIT THIS FILE - it is machine generated */
02 #include <jni.h>
03 /* Header for class org_gnu_readline_Readline */
04 [...]
05 /*
06  * Class:     org_gnu_readline_Readline
07  * Method:    initReadlineImpl
08  * Signature: (Ljava/lang/String;)V
09  */
10 JNIEXPORT void JNICALL Java_org_gnu_readline_Readline_initReadlineImpl
11   (JNIEnv *, jclass, jstring);
12
13 /*
14  * Class:     org_gnu_readline_Readline
15  * Method:    cleanupReadlineImpl
16  * Signature: ()V
17  */
18 [...]

Magic of Images

Web applications implemented in Java that make intensive use of image editing features frequently rely on JMagick [3]. JMagick is a Java-C interface for ImageMagick, and it's a good example of why JNI programming can be a frustrating experience. One issue here relates to stability across the board. Integrating buggy C code injects atypical problems into your application – very often crashes or memory leaks that gradually drag down the application server.

A second problem is inherent to ImageMagick, whose developers often change the interfaces. That means the JMagick wrapper works only with precisely the ImageMagick version for which it was built. Administrators either need to install a version of ImageMagick that does not match their choice of distribution or compile the JMagick version for precisely the current ImageMagick ABI; however, this involves code changes to JMagick and makes maintaining the code base accordingly difficult.

An alternative called Im4java [4], which is another of my projects, does without the performance benefits of JNI and instead offers a stable, object-oriented interface to ImageMagick. You can integrate this by directly calling the ImageMagick executable (typically convert) via the ProcessBuilder class. This means that the non-Java code runs in a separate process and can never cause any damage.

Scripting

As a compiled, high-level language, Java lacks the benefits of scripting. Some attempts have been made to compensate for these drawbacks. As a result, both approaches work: integrating Java into the scripting language (which makes Java the third-party language) and integrated scripting languages into Java.

An important representative of the first category is Python in its Jython embodiment. This is the implementation of the standard Python language using Java, which makes it possible to import and use Java packages from within Python. This option may seem unnecessary from the Python point of view because CPython has a treasure trove of packages in its repository. However, if you need to integrate legacy Java applications, Jython is definitely an interesting option.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs



Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.

Learn More”>
	</a>

<hr>		    
			</div>
		    		</div>

		<div class=