title |
---|
Interfacing From Non-Java Code |
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.
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.
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.
Strengths | Weaknesses |
---|---|
|
|
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
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.
Strengths | Weaknesses |
---|---|
|
|
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
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).
Solution | Type | Languages | Notes |
---|---|---|---|
Raw JNI | In-process (JNI) | C/C++ |
|
Jace | In-process (JNI) | C/C++ |
|
JunC++ion | In-process (JNI) | C/C++ |
|
JuggerNET | In-process (JNI) | .NET |
|
GCJ | In-process (compiler) | C/C++ (GCC only) |
|
IKVM.NET | In-process (runtime) | .NET/Mono |
|
Pipes | Inter-process (local) | Any |
|
Files | Inter-process (local) | Any |
|
Sockets | Inter-process (messaging) | Any |
|
XML-RPC | Inter-process (messaging) | Many |
|
Ice | Inter-process (ORB) | Several |
|
CORBA | Inter-process (ORB) | Many |
|
Codemesh Shared JVM | Inter-process (ORB) | C++, .NET |
|
Know a great integration solution that we missed? Let us know!