Building a JNI adapter
To build a JNI adapter, follow these steps.
- Examine the existing C++ API and note any data structures that
are not defined in Java. You will need to convert these in your C++
glue code.
- Create a JNI Stub library with native declarations that match
those methods as closely as possible in Java. You will need to do
this for every function exposed in the API that the adapter will
use.
- Run javah to create a C++ header file for the stub
library. Example usage:
javah com.ibm.wbia.TwineBall.jnibridge.JNIStubLibrary
- Implement every function in the resulting header in C/C++. You
will use this code to glue the JNI function signatures to your
API.
- Test every function in the JNI Stub library with a test driver
program.
- Begin coding the adapter as you would a Java adapter, using the
JNI Stub library as the Java API.
Notes:
- As we saw with TwineBall, it may be appropriate to do type
conversions on both sides of the JNI layer.
- Character sets are very important. When we convert Java Unicode
strings to C++ strings in this example, we convert them to UTF-8.
If your application does not handle UTF-8, you'll need to convert
them to your particular codepage. Be very careful when you do this
to either handle all possible Unicode characters, or fail
appropriately.
- On many versions of HP-UX, you will need to declare and call a
_main() function in a shared library to do JNI with C++.
This tells the operating system to initialize the C++ runtime. The
same code on Win32 will fail, so #defines may be necessary
for this porting issue.
Note these points about threading.
- Remember that Java adapters are multi-threaded by default. Your
adapter could be asked to handle multiple service calls on multiple
threads simultaneously. If the native code is not threadsafe, you
may need to single-thread the adapter by using the -t
option in the start script.
- Do not pass Java objects from one thread to another in C++
space, though it's unlikely you'd need to do that in an adapter
anyway.
- Normal rules for synchronization of globally accessible objects
apply.
- You must not pass JNIEnv* from one thread to another,
or depend on the pointer being the same in two different
threads.
The JVM creates a distinct JNI environment for each thread, and the
native code must use only the pointer valid for the current
thread.
