|
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
General Java Java Native Methods
Java Native Methods
By: Steve Schoettler
Jan. 1, 1996 12:00 AM
Native methods are functions written in C or C++, compiled into a library, and dynamically loaded by the Java runtime. This article describes how Java programs can call native methods, and how native C code can create Java objects and invoke Java methods. The examples are written for Windows 95, Windows NT and Solaris, and should be portable to other platforms.
Benefits and Limitations of Native Methods
Why Use Native Methods?
Limitations Portability- A native library must be ported, compiled and tested for each combination of processor and operating system on which the program will run. Security- Because native methods can bypass Java security mechanisms, they don't have any of the built-in runtime protections. You need to convince each user that they should download and use an unrestrained library. Development- If your Java development environment does not also support native code development (many don't), you need to switch back and forth between Java and C development environments. Extra effort is required to ensure dependencies between the two are synchronized. Your object-oriented design may be weakened by the fact that related functionality is split in locations dictated by the demands of library implementations and calling conventions, rather than logic. Maintenance- The number of files and complexity of the source code is higher than for Java-only development projects. A class definition is spread across a .java file, one or more C files, and a header file, all of which must be kept in sync. Changes must be compiled and tested on each supported platform. Native method interfaces aren't part of an existing specification. In a Java implementation from another vendor, or even in a future implementation from Sun, some interfaces could change. For this reason, native code has a higher risk of becoming incompatible with future Java versions than code written entirely in Java. Distribution- Users can't just view your web page to run your applet. They need to get a copy of the library, install it in the correct directory, and correctly set environment variables. Each software update requires a new distribution. Performance- The advances in Java compilation techniques, particularly just-in-time compilers, have narrowed the performance gap between compiled native code and Java to within a few percent for some applications. Java is young and improvements are still coming. A possible alternative: A Java program can communicate with a C program in ways other than through native methods. Both programs could run as separate processes and communicate through shared files or sockets. Socket I/O is used to make HTTP requests to a web server, and to request mail from a POP3 server. Future libraries will provide additional mechanisms. For example, the JDBC library from Sun will allow Java programs to communicate with others through shared databases. In summary, native methods re-introduce many of the problems Java was designed to solve. Sometimes, though, your need is great enough to outweigh the disadvantages. The rest of this article demonstrates how you can create and use native methods.
Native Data Types and Storage
Primitive Types and Objects The access specifiers for the instance data don't matter; native methods can access any instance data, even if it is private. Compile this file and then generate the header file with javah.
javac SimpleClass.java Javah generates a header file SimpleClass.h that includes the declarations shown in Listing 2. Notice that both the integer and boolean take 32 bits of storage. All Java primitive types, except long, float, and double, take 32 bits. Although somewhat inefficient for storage, this format avoids processor alignment and structure padding issues. This simplifies communication and persistence algorithms, and makes the Java runtime more portable to other platforms. The macro HandleTo (SimpleClass) equivalent is shown in Listing 3.
A reference to a SimpleClass object is declared in C as To access the instance data, use the macro unhand() (defined in interpreter.h) as follows: which is equivalent to: Accessing primitive types and objects from C is fairly straightforward. Java provides additional C functions and macros for accessing two special kinds of objects: arrays and strings.
Arrays
HArrayOfInt *intList = The array types are defined in typecodes.h. For an array of any class of objects, use the value T_CLASS. For such arrays, Java identifies the class of object in the array by the value stored in the last slot of the array. An example of code that creates an array of Objects is shown in Listing 4. Some other useful array functions are shown in Table 1.
Strings strlen(cstr));
To convert from a Java string to a C string: The storage allocated by makeCString is temporary, and garbage collected later. If you need to use the string after the native function returns, use malloc to allocate heap memory and copy cstr into the new memory space. Don't call free on memory returned by makeCString. Some other useful string functions are shown in Table 2.
Calling C from Java
The steps required to create and execute native C code are Native methods are declared in Java with the keyword native, and the declarations have no function body. The class SimpleClass2 contains a native add function, as shown in Listing 5. Implement the native method in C as shown in Listing 6. When using a C++ compiler, you may need to surround the include statements with extern "C" { } to tell the compiler that the files follow C syntax conventions. Native method names are of the form class_method. The class includes the package name, with underscores separating the class path components. For example, if String.length() were native, the C function name would be java_lang_String_length. The first parameter of all methods is the object whose method was invoked ¾ I use the variable name self for the instance pointer because this is reserved in C++. To compile, add /java/include;/java/ include/platform (where platform is win32, solaris, etc.) to your include path. Use javah to generate SimpleClass2.h and use javah -stubs to generate a C stub file. The stub file contains a wrapper function to set up the C parameters from values in the Java stack.. Compile the C program and stub file and link them with /java/lib/javai.lib into mylib.dll. Copy the DLL to some directory in your executable path, so that it can be found by System.loadLibrary(). On Solaris, the library should be called libmylib.so and its directory should be included in LD_LIBRARY_PATH. When you run SimpleClass2, the main function loads mylib.dll, calls the add function, and prints the result. Note for Microsoft Foundation Class/Win32 users. Many MFC classes require the current thread to be initialized by CreateThread(), whereas Java uses _beginthreadex() to create all its threads in Win32 platforms. To use MFC classes, your native method must create another thread with the CreateThread() function, and then create and invoke MFC objects from within that new thread. Your DLL must also include a DLLMain function to call the Afx initialization and cleanup routines appropriately. If you aren't using MFC in your native method DLL, don't worry about any of this. Note for Netscape users: To use a DLL with Netscape, it needs to be linked with a Netscape library instead of javai.dll, and placed inside Netscape's execution directory program/ java/bin. As of this writing, that library is not part of the standard Netscape distribution, but they do have some developer kits. See their web page for more information.
Calling Java from C The following examples assume that the functions are called from a C native method that was called from Java. In other words, the flow of control goes from Java to C back to Java again. A C program can call into Java, but there are several complexities that make it beyond the scope of an introductory article. In a future article in this series, I will show how to call Java asynchronously from C.
The Basic Functions The return value is the return value of the method, which may have to be cast to the appropriate type.
To create an instance, use:
To call a Java class method, use:
Description of Parameters The environment is a function of the calling stack and the current task. The current environment can be obtained by calling the function EE(). In the execute_... functions, you can pass a value of 0 for ee and the called function calculates the correct environment by calling EE().
Internal class names include the entire package path, with each term separated by a "/". For example, the Java class java.lang.String would be referred to in C as "java/lang/String". For the call to execute_java_constructor, either the class name or cb should be supplied, but not both. The other parameter should be 0. in the form ( parameter_types ) return_value Parameter types are a series of the following: array `[' + array type byte `B' char `C' class `L' + class name + ;' float `F' double `D' int `I' long `J' short `S' void `V' boolean `Z' Some examples are shown in Table 3.
This pointer is the base of all the information about a class, including its method table and descriptions of each field. To get the class pointer from a class object, use: ClassClass *cb = unhand(cls) To get the class pointer from a class name, use: ClassClass *cb = FindClass(0, classname, TRUE); If the class has not yet been loaded, this call causes the class to be loaded from the CLASSPATH.
To get the class pointer from one of its instances, use For the call to execute_java_constructor, either the class name or cb should be supplied, but not both. The other parameter should be 0.
Exceptions
There can be only one pending exception per execution environment. If you use execute_java_dynamic_method and the called method throws an exception, that exception information is overwritten if you throw another one with SignalError. You can check whether an exception has been thrown with Although the Java compiler has no way to know which exceptions your native code might throw, you should still want to add "throws" clauses to the native methods declarations in Java as a form of documentation.
Conclusion Reader Feedback: Page 1 of 1
Latest Cloud Developer Stories
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week
Breaking Cloud Computing News
|
|||||||||||||||||||||||||||||||||||||||||||||||||