Reducing redundant code by wrapping JNI functions.

My HelloWorldNative.c, with the "nativePrintObject" function reduced by wrapping the object and integer field retrieval:


JNIEXPORT void JNICALL Java_helloworld_Main_nativePrintObject(JNIEnv *env, jobject ths, jobject wsv)
{
jint ipAddress;
jstring jPageVisited;
char *pageVisited;
jstring jRefererURL;
char *refererURL;
jobject ipObject;

ipAddress = getIntegerField(env, wsv, "ipAddress");
printf(" wsv.ipAddress = %d.%d.%d.%dn",
( ipAddress & 0xff000000 ) >> 24,
( ipAddress & 0x00ff0000 ) >> 16,
( ipAddress & 0x0000ff00 ) >> 8,
ipAddress & 0x000000ff);

if(!(jPageVisited = getStringField(env, wsv, "pageVisited"))) {
return;
}

pageVisited = (*env)->GetStringUTFChars(env, jPageVisited, 0);

if(!pageVisited) {
return;
}
printf(" wsv.pageVisted = %sn", pageVisited);
(*env)->ReleaseStringUTFChars(env, jPageVisited, pageVisited);

if(!(jRefererURL = getStringField(env, wsv, "refererURL"))) {
return;
}

if(!(refererURL = (*env)->GetStringUTFChars(env, jRefererURL, 0))) {
return;
}
printf(" wsv.refererURL = %sn", refererURL);
(*env)->ReleaseStringUTFChars(env, jRefererURL, refererURL);

if(!(ipObject = getObjectField(env, wsv, "ipAddr", "helloworld", "IPAddress"))) {
return;
}

printf(" wsv.ipAddr = %d.%d.%d.%dn",
getIntegerField(env, ipObject, "byte1"),
getIntegerField(env, ipObject, "byte2"),
getIntegerField(env, ipObject, "byte3"),
getIntegerField(env, ipObject, "byte4")
);
}

jniUtils.h, the header for the JNI wrapper:


/*
* File: jniUtils.h
* Author: thomas
*
* Created on February 10, 2007, 5:30 PM
*/
#include <jni.h>

#ifndef _jniUtils_H
#define _jniUtils_H

#ifdef __cplusplus
extern "C" {
#endif
jint getIntegerField(JNIEnv *env, jobject ths, char *fieldName);
void putIntegerField(JNIEnv *env, jobject ths, char *fieldName, jint ji);
jstring getStringField(JNIEnv *env, jobject ths, char *fieldName);
jobject getObjectField(JNIEnv *env, jobject ths, char *fieldName,
char *objectPackage, char *objectClass);

#ifdef __cplusplus
}
#endif


#endif /* _jniUtils_H */

jniUtils.c, the wrapper for the JNI C interface. Note that not all types have been implemented. Also, error checking may not be performed in all scenarios. See that the "signature" for objects is broken up into package and class name.


#include <stdlib.h>
#include <string.h>
#include "jniUtils.h"

jint getIntegerField(JNIEnv *env, jobject ths, char *fieldName)
{
jclass c;
jfieldID fid;

c = (*env)->GetObjectClass(env, ths);
fid = (*env)->GetFieldID(env, c, fieldName, "I");
return (*env)->GetIntField(env, ths, fid);
}

void putIntegerField(JNIEnv *env, jobject ths, char *fieldName, jint ji)
{
jclass c;
jfieldID fid;

c = (*env)->GetObjectClass(env, ths);
fid = (*env)->GetFieldID(env, c, fieldName, "I");
(*env)->SetIntField(env, ths, fid, ji);
}

jstring getStringField(JNIEnv *env, jobject ths, char *fieldName)
{
jclass c;
jfieldID fid;

return (jstring) getObjectField(env, ths, fieldName, "java/lang", "String");
}

jobject getObjectField(JNIEnv *env, jobject ths, char *fieldName,
char *objectPackage, char *objectClass)
{
char *objectSignature;
jclass c;
jfieldID fid;
jobject objectField = 0;

objectSignature = (char *) malloc(strlen(objectPackage) + strlen(objectClass) + 10);

strcpy(objectSignature, "L");
strcat(objectSignature, objectPackage);
strcat(objectSignature, "/");
strcat(objectSignature, objectClass);
strcat(objectSignature, ";");
c = (*env)->GetObjectClass(env, ths);
fid = (*env)->GetFieldID(env, c, fieldName, objectSignature);

if(!fid) {
return 0;
}
objectField = (*env)->GetObjectField(env, ths, fid);

free(objectSignature);

return objectField;
}