Calling JNI function to create object

Some Name :

I'm writing JNI staff in C11 and have a question about strictly-conforming on-heap object creation.

JNI API provides a function to do this with the following signature:

jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);

As specified in the 6.5.2.2(p7) Standard

The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter.

Arguments corresponding to the ellipsis notation should be explicitly converted to the expected type in order for the code to be conforming. Consider the following case:

public class Event{
    public final int eventType;
    public final String meta;

    public Event(int eventType, String meta){
        this.eventType = eventType;
        this.meta = meta;
    }
}

What types of the arguments I should convert the parameters corresponding to the ellipsis to?

I can guess that it should look as follows:

jclass event_class = ((*env)->FindClass)(env, "f/q/c/n/Event");
jmethodID ctor = (*env)->GetMethodID(
    env, 
    event_class, 
    "<init>", 
    "(ILjava/lang/String;)V"
);
array_element = (*env)->NewObject(
    env, 
    event_class, 
    ctor, 
    (jint) 0, (jobject) NULL //corresponds to the ellipsis
);
Stephan Schlecht :

The types of the arguments are deduced from the method you are calling.

In your case, it is the constructor of the Event class that expects an int and a String.

So it would look like this:

jstring metaStr = (*env)->NewStringUTF(env, "hello");

jobject array_element = (*env)->NewObject(
        env,
        event_class,
        ctor,
        (jint)4711, metaStr
);

Test

To perform a brief test, we could write a class that calls a native C function that creates the desired Event object, initializes it, and returns it to the calling Java side.

This Java program would look like this:

import f.q.c.n.Event;

public class JNIEventTest {

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

    private native Event retrieveNativeEvent();


    public static void main(String[] args) {
        JNIEventTest jniEventTest = new JNIEventTest();
        Event event = jniEventTest.retrieveNativeEvent();
        System.out.println("eventType: " + event.eventType);
        System.out.println("meta: " + event.meta);
    }
}

The native C side would look like this then:

#include "JNIEventTest.h"

JNIEXPORT jobject JNICALL Java_JNIEventTest_retrieveNativeEvent(JNIEnv *env, jobject thisObject) {


    jclass event_class = ((*env)->FindClass)(env, "f/q/c/n/Event");
    jmethodID ctor = (*env)->GetMethodID(
            env,
            event_class,
            "<init>",
            "(ILjava/lang/String;)V"
    );

    jstring eventStr = (*env)->NewStringUTF(env, "hello");

    jobject array_element = (*env)->NewObject(
            env,
            event_class,
            ctor,
            (jint)4711, eventStr
    );

    return array_element;
}

The debug output in the console then looks like this:

eventType: 4711
meta: hello

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=104295&siteId=1