Working with JNI on MAC OSX platform

 In this post, I will discuss about the Java Native Interface(JNI) and Java Virtual Machine(JVM) on Mac OSX.

JNI stands for ‘Java Native Interface’. It will act as an interface between java and other languages. JNI allow a code written written in  languages like C, C++,  Objective-C etc to use java libraries and from java code to use other language code.It means you can call java methods from other languages using JNI and vice versa. Java native methods are flagged by the keyword ‘native’.

Advantages:

  • Use the existing library,
  • Speed of execution,
  • Invoke API functions from product that is developed in C or C++ from a java client and vice versa.

Disadvantages:

  • Run time errors debugging is difficult in native code.An applet can’t call a native methods.
 You can’t say ‘write once run anywhere’.

Introduction to JVM
JVM stands for ‘Java Virtual Machine’. Java Virtual Machine or JVM is a platform independent execution environment that converts Java byte-code into machine code(binary). JVM function is to load the appropriate class files for executing a java program, and then to execute it.

Introduction to JRE
JRE stands for ‘Java RunTime Environment’. JRE includes the JVM, as the JRE provides some standard libraries and the JVM which can be used to execute a java program.

JRE

JNI Types and Data Structures
Java Primitive types and their machine dependent native equivalents.

Primitive Types
Java Type                                                       Native Type

  1. boolean                                                       jboolean
  2. byte                                                              jbyte
  3. char                                                              jchar
  4. short                                                            jshort
  5. int                                                                 jint
  6. long                                                              jlong
  7. double                                                        jdouble
  8. void                                                             void
  9. float                                                            jfloat

Reference Types
The JNI includes a number of reference types that correspond to different kinds of java objects. JNI reference types are organized in the hierarchy as show below:

refTypesJNI

In C , all other JNI reference types are defined to be same as jobject.

Field and Method ID

  • JfieldID for accessing the enum fields of java class.
  • JmethodID for accessing the methods of java class.

Value Types

typedef union jvalue

{

jboolean z;    
jbyte b;
     jchar c;   jshort s;    jint i;    jlong j;    jfloat f;    jdouble d;   jobject l;

} jvalue;
Working with JNI (MAC OSX, Objective-C to Java)

  1. First, we have to add JavaVM.framework in our cocoa application. Then import two header in your file  to use jni functionality (Invocation api and data structures).
    #import <JavaVM/JavaVM.h> to create a reference of JVM. #import <JavaVM/jni.h>
  2. Put your java class file or jar(its like zip folder which contain number of java class files) at path:
  /Library/Java/Extensions

How to access java class in Objective-C ?

To access the java , we need to create the JVM(Java Virtual Machine). After creating JVM and JNI environment , we can access java class in objective-C (Cocoa application).

JavaVM -> interface represents a virtual machine instance. It provides functions that allow, for example threads to attach to a virtual machine instance.
JNIEnv -> interface supports JNI features such as creating objects, accessing fields and calling methods.

Code Snippet:

Consider JavaTest.java as a java file for this code:

JavaTest.java
public class javaTest

{
public static void main(String args[]) {
}
public void display()
{

System.out.println(“Hello”);
}

}
Objective-C Method body

– (void) accessJavaClass
{
JavaVM* jvm;     JNIEnv* env;

JavaVMOption options[1];

options[0].optionString = “-Djava.class.path=.”;

JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;

args.options = options;

args.nOptions = 1;

int envError = JNI_CreateJavaVM(&jvm, (void**) &env, &args);

if (envError == JNI_OK)

{
if ((*jvm)->AttachCurrentThread(jvm, (void**) &env, NULL) == JNI_OK)
{
jclass javaTestCls = (*env)->FindClass(env, “JavaTest”);

if (javaTestCls != nil)
{
NSLog(@”Accessed”);

(*env)->DeleteLocalRef(env, javaTestCls);
}
else
{
NSLog(@”Not Accessed”); }

(jvm[0])->DetachCurrentThread(jvm);
}
}
else
{
NSLog(@”JVM has not created”);
}
}

Here, FindClass API is used to find the class and return class type. It simply receive two parameter JNIENV and class name.

How to create instance of java class in objective-C ?
There are two ways for creating instance of above accessed class.

  1. Without constructor
jobject javaTestObj = (*env)->AllocObject(env, javaTestCls);
  2. Using contructor ID(First we have to get the constructor id of JavaTestCls)
    jmethodID constructID = (*env)->GetMethodID(env, javaTestCls, “<init>”, “()V”);
    jobject javaTestObj = (*env)->NewObject(env, javaTestCls, constructID);

Here , GetMethodID API is used for getting any method id. It takes four parameter env(pointer to JNIEnv), jclass type, name of method and method signature. Here <init> is the default constructor name.
You can get the method signature using terminal command on command prompt(Terminal).
javap -s javaclassname

How to access java methods in Objective-C ?
In this block, trying to access display method and call that method which print hello message at console in xcode.
//Getting method ID
jmethodID methID = (*env)->GetMethodID(env, javaTestCls, “display”, “()V”);

//Calling a display method
(*env)->callVoidMethod(env, javaTestObj, methID);
Here , callVoidMethod used to call void method and it accepts atleast 3 parameters depending that if java method is parameterized method.
Here above i am dealing with non – static method which is not returning any parameter and not receiving any parameter. In case of static methods you have to use following JNI Invocation API.
GetStaticMethodID to create static method ID.
CallStaticVoidMethod to call static void method.

If method return some object value then following JNI Invocation API use.
CallObjectMethod to call method which returning jobject(any object from java) type.(Non – Static Method)
CallStaticObjectMethod to call static method with returning parameter.

If method return non- object kind of value like int boolean etc.
CallIntMethod which return int value. CallBooleanMethod which return boolean value. so on.

How to access java enum fields in Objective-C ?
Like methods, fields also can be static and non-static. Following Invocation api use to access static and non-static enum fields.
GetStaticFieldID to access the static fields.
GetFieldID to access non-static fields.

To get the fields after getting field ID.
GetStaticObjectField in case of static fields. GetObjectField in case of non-static fields.

Code Snippet:
Consider java class of enum type: Colors.java
package com.group.color; public enum Colors
{
RED, BLUE
}
It contains two enum values.

– (void) accessEnumFields
{
JavaVM* jvm; JNIEnv* env;
JavaVMOption
options[0].optionString = “-Djava.class.path=.”;
JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;
args.options = options;
args.nOptions = 1;
int envError = JNI_CreateJavaVM(&jvm, (void**) &env, &args);
if (envError == JNI_OK)
{
if ((*jvm)->AttachCurrentThread(jvm, (void**) &env, NULL) == JNI_OK)
{
jclass colCls = (*env)->FindClass(env, “Colors”);
if (colCls!= nil)
{
jfieldID fieldID = (*env)->GetStaticFieldID(env, colCls, “RED”, “Lcom/group/color/colors;”);
if (fieldID != nil)
{
jobject field = (*env)->GetStaticObjectField(env, colCls, fieldID);
if (field != nil)
{
NSLog(@”Field get accessed”);
(*env)->DeleteLocalRef(env, field);
}
else
{
NSLog(@”Not Accessed”); }
}
options[1];
(*env)->DeleteLocalRef(env, colCls);
}
else
{
NSLog(@”Class not accessible”);
}
(jvm[0])->DetachCurrentThread(jvm);
}
} else
{
NSLog(@”JVM has not created”); }
}

Examples:
Consider a java class which is common for all examples as follows:- Test.java
public class Test
{
public static void main(String args[])
{
}

public void printNumber(int num)
{
System.out.println(num);
}

public void printMess()
{
System.out.println(“Hello Java”);
}

public String getMess()
{
return “Hello Java”;
}
}

And consider one function to check exception if occurred in objective-c file.

– (void) checkException
{
if ((*env)->ExceptionOccured(env))
{
(*env)->ExceptionDescribe(env);
}
}

How to call parameterized method of java class from objective-c using JNI?

– (void) callPrintNumber
{
JavaVM* jvm;
JNIEnv* env;
JavaVMOption options[1];
options[0].optionString = “-Djava.class.path=.”;
JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;
args.options = options;
args.nOptions = 1;
int envError = JNI_CreateJavaVM(&jvm, (void**) &env, &args);
if (envError == JNI_OK)
{
if ((*jvm)->AttachCurrentThread(jvm, (void**) &env, NULL) == JNI_OK)
{
jclass testCls = (*env)->FindClass(env, “Test”);
if (testCls != nil)
{
jobject testObj = (*env)->AllocObject(env, testCls); jmethodID methID = (*env)->GetMethodID(env, testCls, “printNumber”, “(I)V”);
if (methID != nil)
{
(*env)->CallVoidMethod(env, testObj, methID,100);
}
else
{
[self checkException];
}
(*env)->DeleteLocalRef(env, testObj);
(*env)->DeleteLocalRef(env, testCls);
}
else
{
[self checkException];
}
(jvm[0])->DetachCurrentThread(jvm);
}
} else
{
NSLog(@”JVM has not created”);
}
}

Here, i am passing value 100(int type) from objective-c to java method which is get printed in console.

This way, we can use a already built java library in our XCode project.

Written By: Yogesh Arora, Software Engineer, Mindfire Solutions

Advertisements

About yogesha2014

Currently, i am working in MindfireSolution as cocoa application developer. I have 2+ year of experience in mac desktop application development. Also have knowledge about VC++ win32, MFC and MonoDevelop GTK#2.0.

Posted on January 31, 2014, in Cocoa Application, Objective-C and tagged , , , , , , , . Bookmark the permalink. 2 Comments.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: