NB: This article was written circa 2009. While it has been lightly
updated since, much of the information here is now quite outdated.
Nonetheless, the core distinction between in-process and interprocess
remains useful, even if some of the examples highlighted are not
up-to-date anymore.
Interfacing From Non-Java Code
Software written in Java is easiest to use with other Java code.
However, it is possible to call Java code from a program written in
another language. But how to do so depends on your program’s needs.
Technologically, there are two broad categories of solutions:
in-process approaches, and interprocess communication. See
below for discussion and examples of each.
For further reading, check out Codemesh’s technology
comparison.
In-process approaches
With an in-process approach, your
application directly invokes Java code, either by spawning its own
internal Java Virtual Machine (JVM) and passing data across a bridge, or
otherwise executing the Java code within a single environment.
- Tight (API-level) integration
- Minimal performance overhead
- Few security considerations
|
- No shared state between processes
- Limited portability
|
Paradigms:
- JNI – The most common paradigm is the Java Native
Interface, an
API for interfacing Java programs with
native C/C++
code. Functionality exists to 1) call C/C++ methods from Java,
and 2) spawn a Java Virtual Machine and execute Java instructions
from C/C++. The latter direction, known as Java
Invocation,
is the relevant one for calling Java code from C++. Because using
the JNI directly involves writing a lot of tedious glue code,
several projects have emerged for autogenerating such code. See
below: raw JNI, Jace, JunC++ion, JuggerNET
- Compilers – The dominant paradigm in Java is to compile Java
source to Java bytecode, then execute the bytecode in a Java
interpreter. However, an alternative is to compile the Java source
directly to native code so that it can link with other native
programs. Such an approach requires that the compiler provide
correct support for all necessary Java standard library features. It
may also exhibit much different performance (for better or for
worse) than Sun’s Java implementation does. See below: GCJ
- Runtimes – The safest way to guarantee correct program behavior is
to execute Java bytecode using the Java interpreter(s) with which it
has been tested. However, a Java runtime written using a specific
framework (e.g., .NET) could enable seamless integration with other
(non-Java) programs within the same framework. Like the
compiler-based paradigm above, though, it is reliant on the
correctness, completeness and performance of the Java implementation
in question. See below: IKVM.NET
Interprocess communication
The other approach is interprocess
communication,
a broad collection of techniques for exchanging data between multiple
running programs. Such techniques take many forms in computing; one
ubiquitous example is web browsers and web servers. Most solutions in
this category are some form of
middleware.
- Share state between multiple processes on multiple machines
- Broad portability and language support
|
- Object marshalling incurs significant overhead
- Potentially vulnerable to security exploits
|
Paradigms:
- Local communication – Modern operating systems provide several
ways to share information between processes, including shared
memory, file system access, and passing data back and forth with
standard input and output
streams. See below:
pipes, files
- Messaging – Networking technology allows a process on one computer
to send and receive messages from another process on a different
machine. The
client-server model
is probably most applicable for Java/native integration, with the
Java portion acting as a server that can be queried from the native
code. See below: sockets, XML-RPC
- ORB – An object request
broker (ORB) is
a high-level form of middleware for transferring objects between
multiple running programs. ORBs provide an abstraction that can
reduce and simplify code written by providing access to a wealth of
higher-level messaging features. See below: Ice, CORBA, Codemesh
Shared JVM
List of solutions
It is a significant challenge to access a complex Java API from code
written in another language, especially in a cross-platform and high
performance way. The table below provides an overview of viable
approaches, with links to source code and instructions where
appropriate. Which approach to use depends on your application’s target
platforms and languages, and the interaction model between your
application and the Java code—see the discussion of in-process solutions
versus interprocess communication above for details.
A note about SWIG. The Simplified Wrapper and Interface
Generator (SWIG) is an excellent tool for
exposing C++ functionality to higher level languages such as Java.
Unfortunately, calling native code from Java is the wrong direction for
our purposes. However, when combined with an integration solution
specific to C++, SWIG could be used to extend that solution into other
languages (see SWIG’s list of supported
languages for a
complete list).
Raw JNI |
In-process (JNI) |
C/C++ |
- You can code your integration layer using pure JNI calls (but we don't recommend it).
- Low-level JNI offers full control over the interface between Java and native code.
- Raw JNI solutions are time-consuming and error-prone to implement.
- We have coded a simple example for calling the Bio-Formats library in this way.
- We recommend a higher level integration solution such as Jace instead.
|
Jace |
In-process (JNI) |
C/C++ |
- Jace generates C++ proxy classes, one per Java class, mirroring the original functionality as much as possible.
- The C++ proxy classes use JNI under the hood but handle most of the usual JNI pitfalls.
- We provide a set of Bio-Formats C++ bindings using Jace.
|
JunC++ion |
In-process (JNI) |
C/C++ |
- JunC++ion is a commercial in-process integration solution for C/C++ available from Codemesh, Inc.
|
JuggerNET |
In-process (JNI) |
.NET |
- JuggerNET is a commercial in-process integration solution for .NET available from Codemesh, Inc.
|
GCJ |
In-process (compiler) |
C/C++ (GCC only) |
- GCJ can compile Java code into machine code.
- Instead of JNI, GCJ uses its Compiler Native Interface (CNI) to enable access to Java code from C++.
- Works with GCC only (i.e., not with Microsoft Visual C++ or other compilers).
- Correctness and performance is dependent on the compiler implementation.
|
IKVM.NET |
In-process (runtime) |
.NET/Mono |
- IKVM.NET interprets Java byte code on the fly into the .NET/Mono framework.
- Interoperability is limited to applications in the .NET/Mono framework.
- Correctness and performance is dependent on the runtime implementation.
|
Pipes |
Inter-process (local) |
Any |
- Pipes can work well when quantity of data being transferred is limited.
- Be careful about blocking operations causing deadlock.
- The OME Perl server uses a combination of pipes and files to interface with the Bio-Formats library.
|
Files |
Inter-process (local) |
Any |
- Communication via files is slower than pipes, since messages go through disk.
- The size of the communication buffer is limited only by available disk space.
- The OME Perl server uses a combination of pipes and files to interface with the Bio-Formats library.
|
Sockets |
Inter-process (messaging) |
Any |
- You can use a sockets API directly to create a custom solution (but we don't recommend it).
- JVMLink was our first cut at such a solution, before we realized that we were essentially inventing our own middleware.
- We recommend using Ice or CORBA instead.
|
XML-RPC |
Inter-process (messaging) |
Many |
- XML-RPC is a cross-platform remote procedure call (RPC) technology using XML.
- XML-RPC is a human readable, but inefficient, means of transporting information.
- See also: SOAP
|
Ice |
Inter-process (ORB) |
Several |
- Ice is high-performance middleware for cross-platform client/server communication.
- ZeroC argues that Ice is superior to CORBA.
- The OMERO server uses Ice extensively to provide client/server interoperability cross-language.
|
CORBA |
Inter-process (ORB) |
Many |
- Java RMI over IIOP enables communication between Java and other CORBA-supported languages.
- CORBA is a mature technology with widespread use in the enterprise community.
- Support for CORBA is built in to the Java 2 platform.
- Nonetheless, where possible we suggest you use Ice instead.
|
Codemesh Shared JVM |
Inter-process (ORB) |
C++, .NET |
- The Codemesh Shared JVM is a commercial interprocess integration solution available from Codemesh, Inc.
|
Know a great integration solution that we missed? Let us
know!