Возвращение класса С++ на 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 (ну, я добавляю некоторые данные для пересчета, но это довольно продвинуто). Надеюсь, что это поможет.
Искусство