The name "Jirk++" stands for "Java Hierarchy in C++" (it is pronounced "Jeerk" like in "Jeep"). This mechanism provides an easy manipulation of Java classes directly in C++. It is based on the Java Native Interface (JNI) provided with any Java development kit (e.g. the Java Development Kit of Sun Microsystems).
JNI provides low-level functions in C to interact with the Java Virtual Machine (JVM) and all the components it manages, more specifically any Java class or object you want. It is a complete and efficient interface but it is difficult to manipulate it, the access to a single class can take several lines of C code and requires some knowledge of JNI's mechanism. Jirk++ proposes an encapsulation of these low-level functions and the mapping of any Java class you want so you can manipulate them as if they were C++ classes.
The goals of Jirk++ are to provide an easiest way to use C++ code in Java and to provide a fully portable graphic interface for C++ through the possibility of using directly Java components. Jirk++ is, for the moment, part of the of which the binary code and the source code are free of charge to use, access or modify under .
This document first presents briefly JNI and its facilities. Then we introduce Jirk++, its mechanism and how it can be useful. The rest of the section explains how to use Jirk++ through some examples.
JNI is an interface between Java and C/C++ code. It is possible to call a C/C++ function from Java code. You just have to declare a method in your Java class that is specified as "native", meaning the core of the function is native code, i.e. machine dependent code. In C/C++, you have to define a function that will be recognized as the native method of your class, the identification of the function is performed using its name. For instance, the method named
Of course, these C/C++ functions can receive arguments. Some of them are needed for technical issues (e.g. which JVM is used) and the others are classical arguments as any Java method can receive. So the C/C++ functions representing Java native methods can receive primitive types from Java (like integers, floating points, booleans...) and references to Java objects. JNI provides facilities to manipulate these references from the C/C++ side.
This mechanism is interesting if your application is Java oriented and if you only need limited interaction with C++. But if your application is mostly C++ oriented, you may prefer to load a JVM into your C/C++ program and use Java from there. Fortunately JNI extends its facilities to manipulate Java classes within any C/C++ function, not only those representing a Java native method.
To resume, from the Java side you can only call C/C++ functions with eventually Java arguments, but you can not manipulate structures or classes of the C/C++ side. From the C/C++ side, you have more facilities and you can manipulate anything you want from the Java side. If you want to know more about JNI, here is an excellent book (the one we use to develop Jirk++): The Java Native Interface: Programmer's Guide and Specification, Sheng Liang, 1999, Addison-Wesley. You can find parts of this book in The Java Tutorial.
Jirk++ only works on the C/C++ side, so nothing from the Java side has changed compared to JNI. Jirk++ proposes first an encapsulation of the C functions of JNI into C++ classes to mask the complex JNI mechanism and provides a fully object-oriented interface. Hence, you do not have to know details on JNI to load, for instance, a JVM into your C++ program. Jirk++ also provides, and it is its most important contribution, a C++ representation of any Java class you want so you can manipulate it as a C++ class. At your request, Jirk++ can create a C++ class that possesses the same methods, attributes and inheritance as the Java class it represents. This encapsulation has naturally a cost, Jirk++ will obviously be slower than a direct and efficiently-designed call to JNI. In a specific situation, a good programmer will do a better job that the generic approach of Jirk++. When designing Jirk++, we favored easiness of use to efficiency of execution.
Jirk++ is useful if you want for instance a portable graphic interface for a C++ program. For that, you have to load a JVM, then you can call Java classes as any C++ class in your program. Nowadays we can suppose that any environment has a JVM or can easily get one. Jirk++ is also useful if you want to use C++ functions from the Java side (for performance or reuse reasons), because Jirk++ can manipulate the Java arguments received as C++ elements. The following of this section explains how to get Jirk++ and presents some examples on how to use it.
As we said before, Jirk++ is part of the B++ Library which is a C++/Java library. To get Jirk++, you will have to download the B++ Library and compile it (at least the modules needed for Jirk++). Unfortunately, due to our goal of portability and the fact that it is a hybrid library (both Java and C++ code), the compilation is a bit tricky. The B++ Library and documentation are available . Jirk++ is contained in the
With each Java class is associated a C++ class that maps its attributes and methods, e.g. the class named
When you use a Java class, the header file containing the interface of its C++ representation must be included in the C++ code. For instance, for the
The inheritance hierarchy of Java is reproduced in C++, e.g. as the
The primitive types of Java are represented in C++ with a name beginning with the letters
When a function receives arguments from Java, it will always be either primitive types or JNI references to objects that will have the
All the properties of a Java class begin with the letters
Java strings are represented by the
Jirk++ provides a generic class to represent unidimensional or multidimensional Java arrays. The class is
To access an element of an array, you must use the operator
For these examples, we suppose that the JVM is loaded manually into the program, which means it is C++ that calls Java. We will see later an example where it is Java that calls C++.
The following example defines a function that creates a vector with 10 strings containing "message".
Note that the variable
In the C++ example above, the braces (i.e.
The following example defines a function that displays on the standard output the strings contained in a vector.
Here is the equivalent Java code of the function.
In this example, there is no loading of the JVM, we suppose it is done before. In fact, you have to load the virtual machine at the beginning of your program and unload it at the end. Avoid repetitive loads and unloads of the JVM, it will be extremely time consuming. Moreover, when a JVM is unloaded, everything that was in its memory is lost.
This example shows how to manipulate Java arrays.
Here is the equivalent Java code.
In the C++ example, there is technically only one call to the JVM for the creation of the array. In fact, the array exists once in the Java side and once in the C++ side. When a modification of the array occurs in one side, it does not occur in the other side. The update occurs only when the data of the array needs to be transferred from one side to another. To update explicitly the array in a side, you call either the
We present here how to call a C++ function from the Java side. For that, you first have to declare a native method in a Java class to represent the function you want to call. Somewhere in the Java class, you also need to load the dynamic library in which the function is embedded, using the
In the C++ side, the function associated with the
The first argument received is what we call the JNI context or environment. It is through this object that we communicate with a JVM. The second argument is a JNI reference to the object the native method belongs to. The other arguments represent those of the Java method. In our case, there is only a string for which we receive a JNI reference.
The first thing to do is to get the JVM that calls the function. For that, we must use the
As you can see in the example, it is possible for a native method to return an object to Java. Technically, it is a JNI reference that is returned. That explains we do not use directly the
Exceptions thrown from Java can be checked or caught in C++ with a call to methods of the current JNI context, which you can get by calling the default constructor of
From C++, Java exceptions can be thrown using the
Even if you have several threads in your application, there can be only one JVM. In order that a thread can use the JVM, it must be attached to it using the
By default Jirk++ proposes a C++ representation of some usual Java classes. If you want to add other classes, you have to use the following command from the root folder of the B++ Library.
The examples presented here try to show how Jirk++ can facilitate the manipulation of Java elements in C++. Everything is not shown and for more information you will have to look at the documentation of the