Вызов функции JNI для создания объекта - PullRequest
3 голосов
/ 18 мая 2019

Я пишу персонал JNI в C11 и у меня есть вопрос о строго соответствующем создании объекта в куче.

JNI API предоставляет функцию для этого со следующей подписью:

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

Как указано в 6.5.2.2(p7) стандарте

Многоточие в объявлении прототипа функции вызывает Преобразование типа аргумента для остановки после последнего объявленного параметра.

Аргументы, соответствующие многоточечной нотации, должны быть явно преобразованы в ожидаемый тип для соответствия кода. Рассмотрим следующий случай:

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

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

В какие типы аргументов я должен преобразовывать параметры, соответствующие многоточию?

Я могу предположить, что это должно выглядеть следующим образом:

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
);

1 Ответ

1 голос
/ 18 мая 2019

Типы аргументов выводятся из метода, который вы вызываете.

В вашем случае, это конструктор класса Event, который ожидает int и String.

Так бы это выглядело так:

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

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

Test

Чтобы выполнить краткий тест, мы могли бы написать класс, который вызывает собственную функцию C, которая создает требуемый объект Event, инициализирует его и возвращает его вызывающей стороне Java.

Эта Java-программа будет выглядеть так:

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);
    }
}

Тогда нативная сторона C будет выглядеть так:

#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;
}

Выходные данные отладки в консоли выглядят следующим образом:

eventType: 4711
meta: hello
...