Nocturnal
Nocturnal

Reputation: 33

How to access JSON data passed to c in jni?

My java program passes JSONObject to native program like this:

import org.json.simple.JSONObject;

class json{

static{
    System.loadLibrary("json");
}

private native void json(JSONObject j);

public static void main(String args[]){
    json js = new json();
    JSONObject j = new JSONObject();
    j.put("name","someone");
    j.put("age", 15);
    js.json(j);

}
}

how to access these data in c?

#include<stdio.h>
#include<jni.h>
#include "json.h"
#include "cJSON.h"

JNIEXPORT void JNICALL Java_json_json(JNIEnv *env, jobject obj, jobject j){


return;
}

i couldn't find any reference on how to access json data from jobject in c. I'm new to jni. is there any other way to do it?

Upvotes: 3

Views: 1381

Answers (1)

rtoijala
rtoijala

Reputation: 1209

Accessing the JSON data from the C code via JNI is not much different from accessing it via Java. In Java you would write:

System.out.println("name = " + j.get("name"));
System.out.println("age = " + j.get("age"));

The C code is basically the same, just much more verbose, since

  1. You need to get the class object to call methods on them
  2. You need to construct jstring instances for the keys passed to get
  3. You must convert the jstring you get from j.get("name") to a C string
  4. You must release that string after use
  5. You must manually unbox the java.lang.Integer that you get

The code below does just that:

#include<stdio.h>
#include<jni.h>
#include "json.h"
// Notice that "cJSON.h" is not needed

JNIEXPORT void JNICALL Java_json_json(JNIEnv *env, jobject obj, jobject json) {

    // Get the Class object for JSONObject.
    jclass JSONObjectClass = (*env)->GetObjectClass(env, json);

    // Get the ID of the "get" method that we must call.
    // Notice that due to type erasure, both the parameter and the return value
    // are just plain Objects in the type signature.
    jmethodID getID = (*env)->GetMethodID(env, JSONObjectClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
    if (getID == NULL) return;

    // Create java.lang.String instances for the keys we pass to j.get.
    jstring nameKey = (*env)->NewStringUTF(env, "name");
    jstring ageKey = (*env)->NewStringUTF(env, "age");
    if (nameKey == NULL || ageKey == NULL) return;

    // Actually get the name object. Since we know that the value added
    // in the Java code is a string, we just cast the jobject to jstring.
    jstring name = (jstring) (*env)->CallObjectMethod(env, json, getID, nameKey);
    if (name == NULL) return;

    // Get a C string that can be used with the usual C functions.
    const char *name_cstr = (*env)->GetStringUTFChars(env, name, NULL);
    if (name_cstr == NULL) return;

    printf("name = %s\n", name_cstr);

    // Once done, the string must be released.
    (*env)->ReleaseStringUTFChars(env, name, name_cstr);
    name_cstr = NULL;

    // Get the java.lang.Integer object representing the age.
    jobject ageObj = (*env)->CallObjectMethod(env, json, getID, ageKey);
    if (ageObj == NULL) return;

    // Unbox the java.lang.Integer manually.
    jclass IntegerClass = (*env)->GetObjectClass(env, ageObj);
    jmethodID intValueID = (*env)->GetMethodID(env, IntegerClass, "intValue", "()I");
    if (intValueID == NULL) return;

    jint age = (*env)->CallIntMethod(env, ageObj, intValueID);

    printf("age = %d\n", (int) age);
}

More complicated use is done the same way: Check what you would write in Java, and find a way to call the same methods with the same values in C using the JNI functions.

Upvotes: 1

Related Questions