Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send a HashMap from Java to C via JNI

I have an Object that has a HashMap field. When the Object is passed to C, how can I access the field?

The Object's Class has the following fields:

private String hello;
private Map<String, String> params = new HashMap<String, String>();
like image 784
David Avatar asked May 31 '13 05:05

David


1 Answers

The answer to your question really boils down to why you'd want to pass a Map to C rather than iterate your Map in Java and pass the contents to C. But, who am I to question why?

You ask how to access the HashMap (in your provided code, Map) field? Write an accessor method for it in Java and call that accessor method from C when you pass the container Object. Below is some bare-bones sample code showing how to pass a Map from Java to C, and how to access the size() method of the Map. From it, you should be able to extrapolate how to call other methods.

Container Object:

public class Container {

    private String hello;
    private Map<String, String> parameterMap = new HashMap<String, String>();

    public Map<String, String> getParameterMap() {
        return parameterMap;
    }
}

Master Class which passes a Container to JNI:

public class MyClazz {

    public doProcess() {

        Container container = new Container();
        container.getParameterMap().put("foo","bar");

        manipulateMap(container);
    }

    public native void manipulateMap(Container container);
}

Relevant C function:

JNIEXPORT jint JNICALL Java_MyClazz_manipulateMap(JNIEnv *env, jobject selfReference, jobject jContainer) {

    // initialize the Container class
    jclass c_Container = (*env)->GetObjectClass(env, jContainer);

    // initialize the Get Parameter Map method of the Container class
    jmethodID m_GetParameterMap = (*env)->GetMethodID(env, c_Container, "getParameterMap", "()Ljava/util/Map;");

    // call said method to store the parameter map in jParameterMap
    jobject jParameterMap =  (*env)->CallObjectMethod(env, jContainer, m_GetParameterMap);

    // initialize the Map interface
    jclass c_Map = env->FindClass("java/util/Map");

    // initialize the Get Size method of Map
    jmethodID m_GetSize = (*env)->GetMethodID(env, c_Map, "size", "()I");

    // Get the Size and store it in jSize; the value of jSize should be 1
    int jSize = (*env)->CallIntMethod(env, jParameterMap, m_GetSize);

    // define other methods you need here.
}

Of note, I'm not crazy about initializing methodIDs and classes in the method itself; this SO Answer shows you how to cache them for re-use.

like image 153
JoshDM Avatar answered Oct 27 '22 10:10

JoshDM