Calling Java Methods


Of course, Java programming language functions can call C functionsthat is what native methods are for. Can we go the other way? Why would we want to do this anyway? The answer is that it often happens that a native method needs to request a service from an object that was passed to it. We first show you how to do it for non-static methods, and then we show you how to do it for static methods.

Non-Static Methods

As an example of calling a Java method from native code, let's enhance the Printf class and add a method that works similarly to the C function fprintf. That is, it should be able to print a string on an arbitrary PrintWriter object.

 class Printf3 {    public native static void fprint(PrintWriter out, String s, double x);      . . . } 

We first assemble the string to be printed into a String object str, as in the sprint method that we already implemented. Then, we call the print method of the PrintWriter class from the C function that implements the native method.

You can call any Java method from C by using the function call


(*env)->CallXxxMethod(env, implicit parameter, methodID, explicit parameters)

Replace Xxx with Void, Int, Object, etc., depending on the return type of the method. Just as you need a fieldID to access a field of an object, you need a method ID to call a method. You obtain a method ID by calling the JNI function GetMethodID and supplying the class, the name of the method, and the method signature.

In our example, we want to obtain the ID of the print method of the PrintWriter class. As you saw in Volume 1, Chapter 12, the PrintWriter class has several overloaded methods called print. For that reason, you must also supply a string describing the parameters and return the value of the specific function that you want to use. For example, we want to use void print(java.lang.String). As described in the preceding section, we must now "mangle" the signature into the string "(Ljava/lang/String;)V".

Here is the complete code to make the method call, by

  1. Obtaining the class of the implicit parameter;

  2. Obtaining the method ID;

  3. Making the call.

     /* get the class */ class_PrintWriter = (*env)->GetObjectClass(env, out); /* get the method ID */ id_print = (*env)->GetMethodID(env, class_PrintWriter, "print", "(Ljava/lang/String;)V"); /* call the method */ (*env)->CallVoidMethod(env, out, id_print, str); 

Examples 11-14 and 11-15 show the Java code for a test program and the Printf3 class. Example 11-16 contains the C code for the native fprint method.

NOTE

The numerical method IDs and field IDs are conceptually similar to Method and Field objects in the reflection API. You can convert between them with the following functions:

 jobject ToReflectedMethod(JNIEnv* env, jclass class, jmethodID methodID);    // returns Method object methodID FromReflectedMethod(JNIEnv* env, jobject method); jobject ToReflectedField(JNIEnv* env, jclass class, jfieldID fieldID);    // returns Field object fieldID FromReflectedField(JNIEnv* env, jobject field); 


Static Methods

Calling static methods from native methods is similar to calling non-static methods. There are two differences.

  • You use the GetStaticMethodID and CallStaticXxxMethod functions.

  • You supply a class object, not an implicit parameter object, when invoking the method.

As an example of this, let's make the call to the static method

 System.getProperty("java.class.path") 

from a native method. The return value of this call is a string that gives the current class path.

First, we have to find the class to use. Because we have no object of the class System readily available, we use FindClass rather than GetObjectClass.

 jclass class_System = (*env)->FindClass(env, "java/lang/System"); 

Next, we need the ID of the static getProperty method. The encoded signature of that method is

 "(Ljava/lang/String;)Ljava/lang/String;" 

since both the parameter and the return value are a string. Hence, we obtain the method ID as follows:

 jmethodID id_getProperty = (*env)->GetStaticMethodID(env, class_System, "getProperty",    "(Ljava/lang/String;)Ljava/lang/String;"); 

Finally, we can make the call. Note that the class object is passed to the CallStaticObjectMethod function.

 jobject obj_ret = (*env)->CallStaticObjectMethod(env, class_System, id_getProperty,    (*env)->NewStringUTF(env, "java.class.path")); 

The return value of this method is of type jobject. If we want to manipulate it as a string, we must cast it to jstring:

 jstring str_ret = (jstring) obj_ret; 

C++ NOTE

In C, the types jstring and jclass, as well as the array types that are introduced later, are all type equivalent to jobject. The cast of the preceding example is therefore not strictly necessary in C. But in C++, these types are defined as pointers to "dummy classes" that have the correct inheritance hierarchy. For example, the assignment of a jstring to a jobject is legal without a cast in C++, but the assignment from a jobject to a jstring requires a cast.


Constructors

A native method can create a new Java object by invoking its constructor. You invoke the constructor by calling the NewObject function.


jobject obj_new = (*env)->NewObject(env, class, methodID, construction parameters);

You obtain the method ID needed for this call from the GetMethodID function by specifying the method name as "<init>" and the encoded signature of the constructor (with return type void). For example, here is how a native method can create a FileOutputStream object.

 const char[] fileName = ". . ."; jstring str_fileName = (*env)->NewStringUTF(env, fileName); jclass class_FileOutputStream = (*env)->FindClass(env, "java/io/FileOutputStream"); jmethodID id_FileOutputStream    = (*env)->GetMethodID(env, class_FileOutputStream, "<init>", "(Ljava/lang/String;)V"); jobject obj_stream    = (*env)->NewObject(env, class_FileOutputStream, id_FileOutputStream, str_fileName); 

Note that the signature of the constructor takes a parameter of type java.lang.String and has a return type of void.

Alternative Method Invocations

Several variants of the JNI functions call a Java method from native code. These are not as important as the functions that we already discussed, but they are occasionally useful.

The CallNonvirtualXxxMethod functions receive an implicit argument, a method ID, a class object (which must correspond to a superclass of the implicit argument), and explicit arguments. The function calls the version of the method in the specified class, bypassing the normal dynamic dispatch mechanism.

All call functions have versions with suffixes "A" and "V" that receive the explicit parameters in an array or a va_list (as defined in the C header stdarg.h).

Example 11-14. Printf3Test.java
  1. import java.io.*;  2.  3. class Printf3Test  4. {  5.    public static void main(String[] args)  6.    {  7.       double price = 44.95;  8.       double tax = 7.75;  9.       double amountDue = price * (1 + tax / 100); 10.       PrintWriter out = new PrintWriter(System.out); 11.       Printf3.fprint(out, "Amount due = %8.2f\n", amountDue); 12.       out.flush(); 13.    } 14. } 

Example 11-15. Printf3.java
  1. import java.io.*;  2.  3. class Printf3  4. {  5.    public static native void fprint(PrintWriter out, String format, double x);  6.  7.    static  8.    {  9.       System.loadLibrary("Printf3"); 10.    } 11. } 

Example 11-16. Printf3.c

[View full width]

  1. #include "Printf3.h"  2. #include <string.h>  3. #include <stdlib.h>  4. #include <float.h>  5.  6. /**  7.    @param format a string containing a printf format specifier  8.    (such as "%8.2f"). Substrings "%%" are skipped.  9.    @return a pointer to the format specifier (skipping the '%') 10.    or NULL if there wasn't a unique format specifier 11. */ 12. char* find_format(const char format[]) 13. { 14.    char* p; 15.    char* q; 16. 17.    p = strchr(format, '%'); 18.    while (p != NULL && *(p + 1) == '%') /* skip %% */ 19.       p = strchr(p + 2, '%'); 20.    if (p == NULL) return NULL; 21.    /* now check that % is unique */ 22.    p++; 23.    q = strchr(p, '%'); 24.    while (q != NULL && *(q + 1) == '%') /* skip %% */ 25.       q = strchr(q + 2, '%'); 26.    if (q != NULL) return NULL; /* % not unique */ 27.    q = p + strspn(p, " -0+#"); /* skip past flags */ 28.    q += strspn(q, "0123456789"); /* skip past field width */ 29.    if (*q == '.') { q++; q += strspn(q, "0123456789"); } 30.       /* skip past precision */ 31.    if (strchr("eEfFgG", *q) == NULL) return NULL; 32.       /* not a floating point format */ 33.    return p; 34. } 35. 36. JNIEXPORT void JNICALL Java_Printf3_fprint(JNIEnv* env, jclass cl, 37.    jobject out, jstring format, jdouble x) 38. { 39.    const char* cformat; 40.    char* fmt; 41.    jstring str; 42.    jclass class_PrintWriter; 43.    jmethodID id_print; 44. 45.    cformat = (*env)->GetStringUTFChars(env, format, NULL); 46.    fmt = find_format(cformat); 47.    if (fmt == NULL) 48.       str = format; 49.    else 50.    { 51.       char* cstr; 52.       int width = atoi(fmt); 53.       if (width == 0) width = DBL_DIG + 10; 54.       cstr = (char*) malloc(strlen(cformat) + width); 55.       sprintf(cstr, cformat, x); 56.       str = (*env)->NewStringUTF(env, cstr); 57.       free(cstr); 58.    } 59.    (*env)->ReleaseStringUTFChars(env, format, cformat); 60. 61.    /* now call ps.print(str) */ 62. 63.    /* get the class */ 64.    class_PrintWriter = (*env)->GetObjectClass(env, out); 65. 66.    /* get the method ID */ 67.    id_print = (*env)->GetMethodID(env, class_PrintWriter, "print", "(Ljava/lang /String;)V"); 68. 69.    /* call the method */ 70.    (*env)->CallVoidMethod(env, out, id_print, str); 71. } 


 Executing Java Methods from C Code 

  • jmethodID GetMethodID(JNIEnv *env, jclass cl, const char name[], const char sig[])

    returns the identifier of a method in a class.

    Parameters:

    env

    The JNI interface pointer

     

    cl

    The class object

     

    name

    The method name

     

    sig

    The encoded method signature


  • Xxx CallXxxMethod(JNIEnv *env, jobject obj, jmethodID id, args)

  • Xxx CallXxxMethodA(JNIEnv *env, jobject obj, jmethodID id, jvalue args[])

  • Xxx CallXxxMethodV(JNIEnv *env, jobject obj, jmethodID id, va_list args)

    call a method. The return type Xxx is one of Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double. The first function has a variable number of argumentssimply append the method parameters after the method ID. The second function receives the method arguments in an array of jvalue, where jvalue is a union defined as

     typedef union jvalue {   jboolean z;   jbyte b;   jchar c;   jshort s;   jint i;   jlong j;   jfloat f;   jdouble d;   jobject l; } jvalue; 

    The third function receives the method parameters in a va_list, as defined in the C header stdarg.h.

    Parameters:

    env

    The JNI interface pointer

     

    obj

    The implicit argument of the method

     

    id

    The method identifier

     

    args

    The method arguments


  • Xxx CallNonvirtualXxxMethod(JNIEnv *env, jobject obj, jclass cl, jmethodID id, args)

  • Xxx CallNonvirtualXxxMethodA(JNIEnv *env, jobject obj, jclass cl, jmethodID id, jvalue args[])

  • Xxx CallNonvirtualXxxMethodV(JNIEnv *env, jobject obj, jclass cl, jmethodID id, va_list args)

    call a method, bypassing dynamic dispatch. The return type Xxx is one of Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double. The first function has a variable number of argumentssimply append the method parameters after the method ID. The second function receives the method arguments in an array of jvalue. The third function receives the method parameters in a va_list, as defined in the C header stdarg.h.

    Parameters:

    env

    The JNI interface pointer

     

    obj

    The implicit argument of the method

     

    cl

    The class whose implementation of the method is to be called

     

    id

    The method identifier

     

    args

    The method arguments


  • jmethodID GetStaticMethodID(JNIEnv *env, jclass cl, const char name[], const char sig[])

    returns the identifier of a static method in a class.

    Parameters:

    env

    The JNI interface pointer

     

    cl

    The class object

     

    name

    The method name

     

    sig

    The encoded method signature


  • Xxx CallStaticXxxMethod(JNIEnv *env, jclass cl, jmethodID id, args)

  • Xxx CallStaticXxxMethodA(JNIEnv *env, jclass cl, jmethodID id, jvalue args[])

  • Xxx CallStaticXxxMethodV(JNIEnv *env, jclass cl, jmethodID id, va_list args)

    call a static method. The return type Xxx is one of Object, Boolean, Byte, Char, Short, Int, Long, Float, or Double. The first function has a variable number of argumentssimply append the method parameters after the method ID. The second function receives the method arguments in an array of jvalue. The third function receives the method parameters in a va_list, as defined in the C header stdarg.h.

    Parameters:

    env

    The JNI interface pointer

     

    cl

    The class of the static method

     

    id

    The method identifier

     

    args

    The method arguments


  • jobject NewObject(JNIEnv *env, jclass cl, jmethodID id, args)

  • jobject NewObjectA(JNIEnv *env, jclass cl, jmethodID id, jvalue args[])

  • jobject NewObjectV(JNIEnv *env, jclass cl, jmethodID id, va_list args)

    call a constructor. The method ID is obtained from GetMethodID with a method name of "<init>" and a return type of void. The first function has a variable number of argumentssimply append the method parameters after the method ID. The second function receives the method arguments in an array of jvalue. The third function receives the method parameters in a va_list, as defined in the C header stdarg.h.

    Parameters:

    env

    The JNI interface pointer

     

    cl

    The class to be instantiated

     

    id

    The constructor method identifier

     

    args

    The constructor arguments




    Core JavaT 2 Volume II - Advanced Features
    Building an On Demand Computing Environment with IBM: How to Optimize Your Current Infrastructure for Today and Tomorrow (MaxFacts Guidebook series)
    ISBN: 193164411X
    EAN: 2147483647
    Year: 2003
    Pages: 156
    Authors: Jim Hoskins

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net