Возвращение класса С++ на Java через JNI

В настоящее время я использую как С++, так и Java в проекте, и я хотел бы иметь возможность отправлять объект, который содержится в С++, на мой интерфейс Java, чтобы изменить его с помощью графического интерфейса пользователя, а затем отправить модификацию обратно в С++.

До сих пор я возвращал ничто, ни int, ни логическое на Java через интерфейс JNI. На этот раз мне нужно отправить объект через интерфейс. Я сделал подобное определение класса доступным как на С++, так и на Java. Я хотел бы знать, как я буду создавать объект, чтобы я мог использовать его в Java.

В С++ у меня есть:

JNIEXPORT MyObject JNICALL Java_ca_X_Y_Z_C_1getMyObject(JNIEnv* env, jclass, jint number);

Эта функция будет вызвана Java, чтобы получить объект со стороны С++ (объект содержится в одноэлементном, легкодоступном).

В конце Java я делаю простой вызов этого метода,

MyObject anObject = C_getMyObject(3);

который должен вернуть мне вновь созданный объект.

В настоящее время Java возвращает мне UnsatisfiedLinkError, когда я выполняю фактический вызов. Что не так?

Ответ 1

Здесь решение, которое я решил использовать:

Во-первых, я бы создал аналогичный объект в Java. Затем, из С++, я мог бы инициировать его и передать все значения.

(C++)
clazz = env->FindClass("java/lang/Integer");
jmethodID method = env->GetMethodID(clazz, "<init>", "(I)V");
return env->NewObject(clazz, method, (jint)anInteger);

Но потом я понял, что это не очень портативно и было слишком сложно.

Вместо этого я решил вернуть строку, которую Java будет анализировать и использовать для инициализации объекта на своей стороне.

(JAVA)
String aString = "valuesoftheobject";
MyObject myObject(aString);

MyObject будет иметь конструктор, который берет строку. Я считаю, что решение является простым и эффективным.

Ответ 2

Если ваш класс MyObject определен в С++, вы не сможете получить доступ к его методам в Java. Я бы попытался определить класс оболочки Java вокруг вашего объекта C:

Java:
public C_Object() {
   handle = createHandle();
}

private native long createHandle(); // or whatever pointer/handle type?

public void doStuff() {
   _doStuff(handle);
}

private native void _doStuff(long handle);

Если вы можете экстраполировать C api вместо этого, вы можете попробовать JNA.

Ваш UnsatisfiedLinkError может быть дополнительным символом в имени вашей функции, как указано выше, или, возможно, он не может обрабатывать возвращаемое значение MyObject?

Ответ 3

Еще один инструмент, на который вы должны обратить внимание, - SWIG. SWIG - отличный инструмент для создания оберток на других языках (таких как Java, Python или С#) для существующих объектов C/С++. Он будет генерировать автоматические оболочки Java вокруг объектов C/С++ и сделать все тяжелое JNI для вас.

Я использую его широко в Xuggler. Чтобы увидеть пример, если вы загружаете исходный код Xuggler, здесь есть объект С++:

csrc/com/xuggle/xuggler/IStreamCoder.h

Я определяю здесь файл интерфейса SWIG:

csrc/com/xuggle/xuggler/IStreamCoder.i

И при запуске через Swig он генерирует объект Java (который здесь хранится)

generate/java/com/xuggle/xuggler/IStreamCoder.java

Мы можем легко получить доступ к этому объекту из Java (ну, я добавляю некоторые данные для пересчета, но это довольно продвинуто). Надеюсь, что это поможет.

Искусство