Listing 1: Passing an int to the JNI

package jni_article_;

public class IntegerAccess {
static {
System.loadLibrary("EasyJNI");
}
private native int accessInt(int value);
// (1)
private int value;
public IntegerAccess() {value = 5;}

public static void main(String[] args) {
IntegerAccess integerAccess1 = new IntegerAccess();
System.out.println("Value sent and returned is " +
integerAccess1.accessInt(integerAccess1.value));
}
}

Listing 2: Native code called in Listing 1

// Headers omitted...
JNIEXPORT jint JNICALL Java_jni_1article_1_IntegerAccess_accessInt
(JNIEnv *, jobject, jint jInt)
{
cout << "Value is " << jInt << endl;

return (jInt);
}

Listing 3: Passing a string parameter from Java to C++

package jni_article_;

public class StringAccess {
static {
System.loadLibrary("EasyJNI");
}
private native String accessString(String stringValue);
public StringAccess() {
}

public static void main(String[] args) {
StringAccess stringAccess1 = new StringAccess();
System.out.println("Value sent and returned is " +
stringAccess1.accessString("Hello World"));
}
}

Listing 4: Native code called in Listing 3

// Headers omitted...
JNIEXPORT jstring JNICALL Java_jni_1article_1_StringAccess_accessString
(JNIEnv *env, jobject jo, jstring jStringValue)
{
jstring jStr = 0;
const char * str =
env->GetStringUTFChars(jStringValue, NULL);
// (1)
if (str) {
cout << "Value is " << str << endl;
jStr = env->NewStringUTF("Goodbye World");
env->ReleaseStringUTFChars(jStringValue, str);
}

return (jStr);
}

Listing 5: Passing a class parameter from Java to C++.

package jni_article_;

public class ClassAccess {
static {
System.loadLibrary("EasyJNI");
}
private native int accessClass(Device1 devName);
private native int accessClass(Device2 devName);
public ClassAccess() {
}

public static void main(String[] args) {
ClassAccess classAccess = new ClassAccess();
Device2 dev2 = new Device2();
classAccess.accessClass(dev2);
}
}

// In device1.java
package jni_article_;

public class Device1 {
public Device1 (int value) {
intValue = value;
}
int intValue;
}

// In device2.java
package jni_article_;

public class Device2 {
public Device2 () {
intValue = 1;
longValue = 11;
stringValue = new String("Hello World");
dev1Value = new Device1(5);
}
private int intValue;
private long longValue;

String stringValue;
Device1 dev1Value;
}

Listing 6: Native code called in Listing 5

// Headers omitted...
// ClassAssign.AccessClass(Device2)
JNIEXPORT jint JNICALL
Java_jni_1article_1_ClassAccess_accessClass__Ljni_1article_1_Device2_2
(JNIEnv *env, jobject jo, jobject jOutput)
{
// get the class of the object parameter
jclass cls0 = env->GetObjectClass(jOutput);
// (1)
if (cls0) {
// get the field ID of the "intValue" field of this class
jfieldID fidInt = env->GetFieldID(cls0, "intValue", "I");
// (2)
if (fidInt) {
// get the value of the field in this instance of the above class
jint valInt = env->GetIntField(jOutput, fidInt);
cout << "Value is " << valInt << endl;

// get the field ID of the "longValue" field of this class
jfieldID fidLong = env->GetFieldID(cls0, "longValue", "J");
// (3)
if (fidLong) {
// get the value of the field in this instance of the above class
jlong valLong = env->GetLongField(jOutput, fidLong);
cout << "Value is " << (long) valLong << endl;

// get the field ID of the String field of this class
jfieldID fidString = env->GetFieldID(cls0, "stringValue",
"Ljava/lang/String;");
// (4)
if (fidString) {
// get the value of the field in this instance of the above class

jstring valString = (jstring) env->GetObjectField(jOutput, fidString);
if (valString) {
const char * str = env->GetStringUTFChars(valString, NULL);
if (str) {
cout << "Value is " << str << endl;
env->ReleaseStringUTFChars(valString, str);

// get the field ID of the Device1 object field of this class

jfieldID fidObject = env->GetFieldID(cls0, "dev1Value", "Ljni_article_/Device1;");
// (5)
if (fidObject) {
// get a reference to this field in this instance of the class
jobject valObject = env->GetObjectField(jOutput, fidObject);
if (valObject) {
// get the class of the object parameter
jclass clsObject = env->GetObjectClass(valObject);
if (clsObject) {
// get the field ID of the "intValue" field of this class
jfieldID fidInt = env->GetFieldID(clsObject, "intValue", "I");
if (fidInt) {
// get the value of the field in this instance of the class
jint valInt = env->GetIntField(valObject, fidInt);
// (6)
cout << "Value is " << valInt << endl;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }


return (0);
}

Listing 7: Functions to handle fetching string and object members of a Java

// class
void AccessString(JNIEnv *env, jclass clsContaining, jobject jContaining, LPCTSTR
lpszFieldName, string & strOut)
{
jfieldID fidString = env->GetFieldID(clsContaining, lpszFieldName,
"Ljava/lang/String;"); // get the field ID of the field of this class
if (fidString) {
jstring valString = (jstring) env->GetObjectField(jContaining, fidString);
// get the value of the field in this instance of the above class
if (valString) {
const char * str = env->GetStringUTFChars(valString, NULL);
if (str) {
strOut = str;
env->ReleaseStringUTFChars(valString, str);
        }
      }
    }
  }

void AccessObject(JNIEnv *env, jclass clsContaining, jobject jContaining, LPCTSTR
lpszFieldName, LPCTSTR lpszFieldSig, jclass *clsContained, jobject *oContained)
{
// Code defensively. Initialize with "failure" values for safety
*clsContained = static_cast<jclass>(*oContained = 0);
// get the field ID of the field of this class
jfieldID fidObject = env->GetFieldID(clsContaining, lpszFieldName, lpszFieldSig);
if (fidObject) {
// get the value of the object field in this instance of the above class
*oContained = env->GetObjectField(jContaining, fidObject);
if (*oContained) {
// get the class of the object parameter
*clsContained = env->GetObjectClass(*oContained);
    }
  }

return;
}

Listing 8: Listing 5 modified to use the access...

// functions
JNIEXPORT jint JNICALL Java_jni_1article_1_ClassAccess_accessClass__Ljni_1article_
1_Device2_2
(JNIEnv *env, jobject jo, jobject jOutput)
{
// get the class of the object parameter
jclass cls0 = env->GetObjectClass(jOutput);
if (cls0) {
// int and long code here...(omitted for clarity)
string sOut;
AccessString(env, cls0, jOutput, "stringValue", sOut);
cout << "Value is " << sOut.c_str() << endl;

jclass clsContained;
jobject oContained;
AccessObject(env, cls0, jOutput, "dev1Value",
"Ljni_article_/Device1;", &clsContained,
&oContained);
if (clsContained && oContained) {
// get the field ID of the intValue field of this
// class
jfieldID fidInt = env->GetFieldID(clsContained,
"intValue", "I");
if (fidInt) {
// get the value of the int field in this instance
// of the above class
jint valInt = env->GetIntField(oContained, fidInt);
cout << "Value is " << valInt << endl;       }
    }
  }

return (0);
}

Listing 9: Assigning C structures to Java classes

package jni_article_;

public class ClassAssign {
static {
System.loadLibrary("EasyJNI");
}
private native int assignClass(Device3 devName);
public ClassAssign() {
}

public static void main(String[] args) {
ClassAssign classAssign = new ClassAssign();
Device3 dev3 = new Device3();
classAssign.assignClass(dev3);
System.out.println("Integer value is "+ dev3.intValue);
System.out.println("Long value is " + dev3.longValue);
System.out.println("String value is " +
dev3.stringValue);
System.out.println("Integer value in Device 1 is " +
dev3.dev1Value.intValue);
    }
  }

Listing 10: Functions to handle assignment of C++ data types to Java fields

// Get an object reference to a Java object type contained within a containing
// Java object.
jobject GetObjectReference(JNIEnv *env, jclass clsStruct, jobject joStruct, LPCSTR
lpszJavaFieldName, LPCSTR lpszSignature)
{
// Get the field ID of the field in the Java object
jfieldID fidField = env->GetFieldID(clsStruct, lpszJavaFieldName, lpszSignature);
if (fidField) {
// get a reference to the SymAPIDirector object
jobject joField = env->GetObjectField(joStruct, fidField);
return (joField);
}
return (0);
}

/*
Assign a C int value to a Java int field.
The Java class is cls0. The Java object is oOutput. The C int value is uiMember.
The Java class member name is lpszJavaFieldName.
Usage:
Return value:
1 => success;
0 => failure;
*/
int ParseIntField(JNIEnv *env, jclass cls0, jobject oOutput, unsigned uiMember, LPCSTR
lpszJavaFieldName)
{
int iRc = 0; // failure

// Get the field ID of the field in the Java object.
// Note the "I" JNI signature for an int.
jfieldID fid0 = env->GetFieldID(cls0, lpszJavaFieldName, "I");
if (fid0) {
// assign the (C++) int field to the Java object
env->SetIntField(oOutput, fid0, uiMember);
iRc = 1; // success
}

return (iRc);
}

/*
Assign a C long value to a Java long field.
The Java class is cls0. The Java object is oOutput. The C long value is lCMember.
The Java class member name is lpszJavaFieldName.
Return value:
1 => success;
0 => failure;
*/
int ParseLongField(JNIEnv *env, jclass cls0, jobject oOutput, long lCMember, LPCSTR
lpszJavaFieldName)
{
int iRc = 0; // failure

// get the field ID of the field in the Java object
jfieldID fid0 = env->GetFieldID(cls0, lpszJavaFieldName, "J");
if (fid0) {
// assign the (C++) long field to the Java object
env->SetLongField(oOutput, fid0, lCMember);
iRc = 1; // success
}

return (iRc);
}

/*
Assign a C single byte string value to a Java object field.
The Java class is cls0. The Java object is oOutput. The C string is lpszCMember.
The Java class member name is lpszJavaFieldName and it's signature is lpszSignature.
Return value:
1 => success;
0 => failure;
*/
int ParseStringField(JNIEnv *env, jclass cls0, jobject oOutput, LPCSTR lpszCMember,
LPCSTR lpszJavaFieldName)
{
int iRc = 0; // failure
// convert C-string member to a java String object
jstring str0 = env->NewStringUTF(lpszCMember);
if (str0) {
// get the field ID of the String field in the Java object
jfieldID fid0 = env->GetFieldID(cls0, lpszJavaFieldName, "Ljava/lang/String;");
if (fid0) {
// assign the (C++) string field to the Java object
env->SetObjectField(oOutput, fid0, str0);
iRc = 1; // success
    }
  }

return (iRc);

Additional Source Code Listings

Listing 11: Native code called in Listing 9

// Headers omitted…
JNIEXPORT jint JNICALL Java_jni_1article_1_ClassAssign_assignClass
(JNIEnv *env, jobject jo, jobject jOutput)
{
int iRc = 0;

// get the class of the object parameter
jclass cls0 = env->GetObjectClass(jOutput);
// (1)
if (cls0) {
// get the field ID of the "intValue" field of this class
jfieldID fidInt = env->GetFieldID(cls0, "intValue", "I");
// (2)
if (fidInt) {
// assign the (C++) int member to the Java object
env->SetIntField(jOutput, fidInt, dev3.intValue);

// get the field ID of the "longValue" field of this class
jfieldID fidLong = env->GetFieldID(cls0, "longValue", "J");
// (3)
if (fidLong) {
// assign the (C++) long member to the Java object
env->SetLongField(jOutput, fidLong, dev3.longValue);

// convert C-string member to a java String object
jstring str0 = env->NewStringUTF(dev3.stringValue);
// (4)
if (str0) {
// get the field ID of the String field in the Java object
jfieldID fidString = env->GetFieldID(cls0, "stringValue",
"Ljava/lang/String;");
if (fidString) {
// assign the (C++) string field to the Java object
env->SetObjectField(jOutput, fidString, str0);

// get the field ID of the object field in the Java object jfieldID fidObject = env->GetFieldID(cls0, "dev1Value", "Ljni_article_/Device1;");
// (5)
if (fidObject) {
// get a reference to the object field in this instance of the class
jobject joDevice1 = env->GetObjectField(jOutput, fidObject);
if (joDevice1) {
// get the class of the object parameter
jclass cls0 = env->GetObjectClass(joDevice1);
if (cls0) {
// get the field ID of the "intValue" field of this class
jfieldID fidInt = env->GetFieldID(cls0, "intValue", "I");
if (fidInt) {
// assign the (C++) int member to the Java object
env->SetIntField(joDevice1, fidInt, dev3.dev1Value.intValue);
iRc = 1; // success
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }

return (iRc);

Listing 12: Listing 11 modified to use the Parse… functions defined in Listing 10

JNIEXPORT jint JNICALL Java_jni_1article_1_ClassAssign_assignClass
(JNIEnv *env, jobject jo, jobject jOutput)
{
int iRc = 0;

// get the class of the object parameter
jclass cls0 = env->GetObjectClass(jOutput);
if (cls0) {
iRc = ParseIntField(env, cls0, jOutput, dev3.intValue,
"intValue");
if (iRc) {
iRc = ParseLongField(env, cls0, jOutput,
dev3.longValue, "longValue");
if (iRc) {
iRc = ParseStringField(env, cls0, jOutput,
dev3.stringValue, "stringValue");
if (iRc) {
jobject joDevice1 = GetObjectReference(env, cls0,
jOutput, "dev1Value",
"Ljni_article_/Device1;");
if (joDevice1) {
// get the class of the object parameter
jclass cls0 = env->GetObjectClass(joDevice1);
if (cls0) {
iRc = ParseIntField(env, cls0, joDevice1,
dev3.dev1Value.intValue,
"intValue");
iRc = 1; // success
            }
          }
        }
      }
    }
  }

return (iRc);
}