Java Native Methods
Java Native Methods
The information in this section reflects the native method API in JDK 1.1 called the Java Native Interface (JNI). The API in JDK 1.0.2 is different. Microsoft uses a their own API in their Java interpreter.
Native Methods
Justification
Reasons to use
Reuse
utilize existing code
Efficiency
use the language most appropriate for the task
Portability
native methods arent portable
Extra work
must use additional tools to generate several kinds of files javah to create special header files compiler to create native method object files various tools to create shared libraries
Native Methods
Compile native methods Add native object code to a UNIX shared library or Windows DLL
under UNIX, if the shared library is not in the current directory, it must be found in LD_LIBRARY_PATH under Windows, if the DLL is not in the current directory, it must be found in PATH
Native Methods
static { System.loadLibrary(Hello); // reference to libHello.so or Hello.dll } had to create an instance since public static void main(String[] args) { the native method is not static HelloWorld hw = new HelloWorld(); hw.displayHelloWorld(); if displayHelloWorld() was a static method } then creating an instance wouldn't be necessary } and "HelloWorld." could be used here
include dot-separated package name if the HelloWorld class is in a package affects name of generated header file and name of the C function
Native Methods
Cant use member functions for native methods Can only use global functions
Native Methods
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: displayHelloWorld no arguments, void return type * Signature: ()V (signatures are explained on page 14) */ JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
the Java object on which the native method was invoked JNI interface pointer used to invoke JNI functions
The JNIEXPORT and JNICALL macros are defined in jni_md.h which is included from jni.h. It contains platform specific definitions.
full method name is formed from package name, class name, and native method name
Open Computing Institute, Inc.
Native Methods
includes jni.h
// The function signature can be copied from HelloWorld.h. JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv* env, jobject obj) { printf("Hello World!\n"); could also use } cout << "Hello World!" << endl;
To run
java HelloWorld
Native Methods
BuildSettingsGeneral
select the Debug directory and the Release directory for each, make fields for Intermediate and Output files in Output Directories empty
ToolsOptionsDirectories
add x\java\include and x\java\include\win32 where x is the location where the JDK is installed
in the Project Workspace window, click on the FileView tab InsertFiles into Project
insert the implementation files (the C/C++ native methods)
BuildBuild project-name.dll
Open Computing Institute, Inc.
Native Methods
ProjectSettingsGeneral
select Settings For: Win32 Debug and Settings For: Win32 Release for each, make fields for Intermediate and Output files in Output Directories empty
ToolsOptionsDirectories
add x\java\include and x\java\include\win32 where x is the location where the JDK is installed
in the Project Workspace window, click on the FileView tab Right-click the files icon and pick Add Files to Project
insert the implementation files (the C/C++ native methods)
BuildBuild project-name.dll
Open Computing Institute, Inc.
Native Methods
Reference types
arrays, strings, and objects passed by reference
native types are jarray, jstring and jobject these are defined in jni.h
10
Native Methods
not a primitive!
public static void main(String[] args) { PrimParam app = new PrimParam(); System.out.println ("result is " + app.takePrimParam(19, 3.14, "Duke")); } }
PrimParam.cpp
#include <iostream.h> #include "PrimParam.h"
JNIEXPORT jdouble JNICALL Java_PrimParam_takePrimParam (JNIEnv* env, jobject obj, jint i, jdouble d, jstring s) { cout << "i=" << i Unicode Text Format << ", d=" << d << ", s=" << env->GetStringUTFChars(s, 0) << endl; return i + d; } not interested in whether it
11
Native Methods
/* * We use inlined functions for C++ so that programmers * can write: * env->FindClass("java/lang/String") * in C++ rather than: * (*env)->FindClass(env, "java/lang/String") * in C. */
12
Native Methods
13
Native Methods
a jmethodId variable naming convention concatenate the name of the Java class and the name of the method
alternative is
env->GetObjectClass (vector);
jclass vectorClass = env->FindClass("java/util/Vector"); jclass doubleClass = env->FindClass("java/lang/Double"); jmethodID vectorSize = env->GetMethodID(vectorClass, "size", "()I"); int size = env->CallIntMethod(vector, vectorSize); cout << "size of Vector is " << size << endl;
jmethodID vectorElementAt = env->GetMethodID(vectorClass, "elementAt", "(I)Ljava/lang/Object;"); jmethodID doubleDoubleValue = env->GetMethodID(doubleClass, "doubleValue", "()D"); jdouble sum = 0; gets the double primitive value jobject object; from a Double type wrapper object jdouble value; for (int i = 0; i < size; ++i) { cout << "calling elementAt(" << i << ")" << endl; object = env->CallObjectMethod(vector, vectorElementAt, i); value = env->CallDoubleMethod(object, doubleDoubleValue); cout << "value = " << value << endl; sum += value; } return sum; }
could maintain data persistence on the C/C++ side by allocating space for data and keeping a pointer to it in a static variable
14
Native Methods
* Type signatures originate from FieldDescriptors in Java bytecode files. See "The Java Virtual Machine Specification" p. 90-91.
15
Native Methods
When invoking JNI functions from C use (*env)->function(env, ). When invoking JNI functions from C++ use env->function().
FindClass
jclass FindClass(JNIEnv* env, const char* name)
GetObjectClass
jclass GetObjectClass(JNIEnv* env, jobject obj)
NewObject
jobject NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, )
clazz is the class of the object to be created methodID is the constructor to be used
get with GetMethodID (see page 18) replace with the constructor arguments
IsInstanceOf
jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz)
16
Native Methods
GetFieldID
jfieldID GetFieldID(JNIEnv* env, jclass clazz, const char* fieldName, const char* signature)
GetField
see p. 14
replace ? with Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double
SetField
void Set?Field(JNIEnv* env, jobject obj, jfieldID fieldID, NativeType value)
replace ? with Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double
Can get and set all fields of the class of the native method regardless of access specifiers
that's correct because native methods are methods of the class that contains the fields
Open Computing Institute, Inc.
17
Native Methods
GetStaticFieldID
jfieldID GetStaticFieldID(JNIEnv* env, jclass clazz, const char* fieldName, const char* signature)
GetStaticField
NativeType GetStatic?Field(JNIEnv* env, jclass clazz, jfieldID fieldID)
replace ? with Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double
SetStaticField
void SetStatic?Field(JNIEnv* env, jclass clazz, jfieldID fieldID, NativeType value)
replace ? with Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double
18
Native Methods
GetMethodID
jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* signature)
for constructors use <init> for name and V for return type in signature
CallMethod
NativeType Call?Method(JNIEnv* env, jobject obj, jmethodID methodID, )
replace ? with Void, Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double replace with the method arguments use NewObject to invoke constructors
19
Native Methods
GetStaticMethodId
jmethodID GetStaticMethodID(JNIEnv* env, jclass clazz, const char* name, const char* signature)
CallStaticMethod
NativeType CallStatic?Method(JNIEnv* env, jclass clazz, jmethodID methodID, )
replace ? with Void, Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double replace with the method arguments
20
Native Methods
These are the functions that work with single-byte characters in the native method. They convert between UTF (used by Java) and ASCII (used by native methods). There are also non-UTF versions that support two-byte Unicode characters.
NewStringUTF
jstring NewStringUTF(JNIEnv* env, const char* bytes)
GetStringUTFLength
jsize GetStringUTFLength(JNIEnv* env, jstring string)
GetStringUTFChars
const char* GetStringUTFChars (JNIEnv* env, jstring string, jboolean* isCopy)
to create a C string from a Java String isCopy is set to indicate whether a copy was made
VM dependent, you dont decide
21
Native Methods
frees the memory allocated for the C string doesn't change the Java String to match the C string
Java Strings are immutable!
22
Native Methods
GetArrayLength
replace ? with Boolean, Byte, Char, Short, Int, Long, Float, or Double useful for constructing a Java array needed for a method argument can't populate with standard C/C++ array syntax
it's a jobject underneath to populate it, create a native array by calling GetScalarArrayElements() and populate the native array with standard C/C++ array syntax (see next page) when finished populating, release it by calling ReleaseScalarArrayElements()
23
Native Methods
GetScalarArrayElements
NativeArrayType Get?ArrayElements (JNIEnv* env, jarray array, jboolean* isCopy)
replace ? with Boolean, Byte, Char, Short, Int, Long, Float, or Double allows a Java array of scalar elements to be accessed as a native array isCopy is set to indicate whether a copy was made
VM dependent, you dont decide
24
Native Methods
ReleaseScalarArrayElements
void Release?ArrayElements (JNIEnv* env, jarray array, NativeArrayType elems, jint mode)
replace ? with Boolean, Byte, Char, Short, Int, Long, Float, or Double supports garbage collection of Java arrays
call regardless of whether a copy was made
set mode to
0 to copy the native array back to the Java array and free the space for the native array JNI_COMMIT to copy back and not free JNI_ABORT to not copy back and free
must be called if a copy was made to copy array values back to the Java array
see isCopy argument to GetScalarArrayElements test whether isCopy == JNI_TRUE
25
Native Methods
useful for constructing a Java array needed for a method argument can't populate with standard C/C++ array syntax
use SetObjectArrayElement below
GetObjectArrayElement
jobject GetObjectArrayElement (JNIEnv* env, jarray array, jsize index)
SetObjectArrayElement
void SetObjectArrayElement (JNIEnv* env, jarray array, jsize index, jobject value)
26
Native Methods
ThrowNew
jint ThrowNew(JNIEnv* env, jclass clazz, const char* message)
Throw
jint Throw(JNIEnv* env, jthrowable obj)
throws an existing exception object necessary to throw exception objects where more than a message must be passed to the constructor
27
Native Methods
28
Native Methods
synchronizes on obj same as entering a synchronized block in Java blocks until the lock is obtained returns zero if successful in obtaining the lock
spec. doesn't say how this could stop waiting and fail
MonitorExit
jint MonitorExit(JNIEnv* env, jobject obj)
same as exiting from a synchronized block in Java returns zero if successful in releasing the lock
spec. doesn't say how this could fail but it could fail if there is not currently a lock on the object
29
Native Methods