Я работаю в JNI с C++, и я создал метод, в котором ряд параметров передается моему нативного методу как jobjectarray. Я хотел бы вызвать конструктор в JNI, используя эти параметры. Однако метод NewObject не принимает массив заданий вместо использования многоточия. Как бы я выполнил эту задачу? Я не знаю, сколько параметров конструктор будет принимать до вызова метода, и строка подписи передается также из java. Конструктор, который я вызываю, не принимает массив в качестве аргумента, вместо этого различные функции одного и того же класса могут быть переданы функции C++, каждая из которых содержит другую подпись метода. Мне нужен мой метод C++, чтобы он мог создать любой объект с его переданными аргументами. Я использую визуальную студию в качестве моей IDE. Я понимаю, что мне может понадобиться массив jvalues, но я не понимаю, как получить это из jobjectarray.Вызов метода NewObject jni с параметрами в jobjectarray
ответ
EDIT:
К сожалению, я не понял ваш вопрос. Вы можете добиться этого с помощью двух других способов, которые JNI API предусматривает создание объектов (от docs):
jobject NewObjectA(JNIEnv *env, jclass clazz,
jmethodID methodID, const jvalue *args);
jobject NewObjectV(JNIEnv *env, jclass clazz,
jmethodID methodID, va_list args);
NewObjectA
Программисты место все аргументы, которые должны быть переданы в конструктор в массиве аргументов jvalues, который сразу же следует за аргументом methodID. NewObjectA() принимает аргументы в этом массиве и, в свою очередь, передает их методу Java, который программист хочет вызвать.
NewObjectV
Программисты разместить все аргументы, которые должны быть переданы в конструктор в ARGS аргумент типа va_list, который непосредственно следует аргумент methodID. NewObjectV() принимает эти аргументы и, в свою очередь, передает их методу Java, который программист хочет вызвать.
Итак, я сделал пример программы, которая показывает, как ее использовать.
Foo.java
public class Foo {
private int bar;
private String baaz;
public Foo(int bar) {
this(bar, "");
}
public Foo(int bar, String baaz) {
this.bar = bar;
this.baaz = baaz;
}
public void method1() {
this.bar++;
System.out.println(bar);
System.out.println(baaz);
}
}
Bar.java
public class Bar {
public Bar() {
}
public static native Foo createFoo(String signature, Object ... params);
}
bar.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Bar */
#ifndef _Included_Bar
#define _Included_Bar
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Bar
* Method: createFoo
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)LFoo;
*/
JNIEXPORT jobject JNICALL Java_Bar_createFoo
(JNIEnv *, jclass, jstring, jobjectArray);
#ifdef __cplusplus
}
#endif
#endif
Bar.c
#include "Bar.h"
#include <stdlib.h>
jobject JNICALL Java_Bar_createFoo
(JNIEnv * env, jclass class, jstring signature, jobjectArray params) {
// method signature in char *
const char * signatureChar = (*env)->GetStringUTFChars(env, signature, 0);
jvalue * args;
int i, size;
// retrieve foo class
jclass fooClass = (*env)->FindClass(env, "LFoo;");
// retrieve foo construtor
jmethodID fooConstructor = (*env)->GetMethodID(env, fooClass, "<init>", signatureChar);
// operate over params
// ...
// TODO: find out a way to retrieve size from constructor
size = 2;
args = malloc(size * sizeof(jvalue));
for (i = 0; i < size; i++) {
args[i].l = (*env)->GetObjectArrayElement(env, params, i);
}
return (*env)->NewObjectA(env, fooClass, fooConstructor, args);
}
Main.java
public class Main {
static {
System.loadLibrary("YOUR_LIBRARY_NAME_HERE");
}
public static void main(String[] args) {
Foo foo = Bar.createFoo("(ILjava/lang/String;)V", -12312141, "foo");
System.out.println(foo);
foo.method1();
foo = Bar.createFoo("(I)V", -12312141, "foo");
System.out.println(foo);
foo.method1();
foo = Bar.createFoo("(I)V", -12312141);
System.out.println(foo);
foo.method1();
}
}
Внимание: это еще не 100% funciontal, потому что я не мог понять, как получить размер аргумента конструктора на основе конструктора подписи.
Это не совсем то, что я пытаюсь сделать. Конструктор, который я вызываю, не принимает массив в качестве аргумента. Проблема в том, что разные версии одного и того же класса могут быть переданы функции C++, каждая из которых содержит другую подпись метода. Мне нужен мой метод C++, чтобы он мог создать любой объект с его переданными аргументами. – popgalop
Это немного сложно, потому что вы прошли мимо jobjectArray
. Это означает, что примитивные типы были помещены в бокс (например, int
s - это java.lang.Integer
экземпляров в вашем массиве), и вам необходимо их удалить, прежде чем передавать их на конструктор.
Что вам нужно сделать, так это разобрать строку подписи метода (это не так плохо, как вы могли бы подумать), пройти через каждый jobject
в свой массив и преобразовать его в соответствующий тип (с использованием преобразования unboxing если необходимо).
К сожалению, нет никакого встроенного способа в JNI для выполнения распаковки, и, таким образом, вы будете иметь, чтобы сделать это вручную, вызывая соответствующие методы боксовых значений (например, Integer.intValue
получить int
с).
Основная идея:
jobject createObject(JNIEnv *env, jclass clazz, jmethodID constructor, const char *argstr, jobjectArray *args) {
int n = env->GetArrayLength(args);
jvalue *values = new jvalue[n];
const char *argptr = argstr;
for(int i=0; i<n; i++) {
jobject arg = env->GetObjectArrayElement(args, i);
if(*argptr == 'B') { /* byte */
values[i].b = object_to_byte(arg);
}
/* cases for all of the other primitive types...*/
else if(*argptr == '[') { /* array */
while(*argptr == '[') argptr++;
if(*argptr == 'L')
while(*argptr != ';') argptr++;
values[i].l = arg;
} else if(*argptr == 'L') { /* object */
while(*argptr != ';') argptr++;
values[i].l = arg;
}
argptr++;
env->DeleteLocalRef(arg);
}
return env->NewObjectA(clazz, methodID, values);
}
object_to_byte
и другие функции преобразования будут определены как функции, которые распаковывать соответствующий тип (например, object_to_byte
будет использовать JNI для вызова java.lang.Byte.byteValue
на данном объекте).
- 1. Вызов метода с параметрами
- 2. Недействительная косвенная ссылка на вызов NewObject
- 3. android jni - Функция NewObject не вызывает конструктор?
- 4. вызов jni-метода из другой библиотеки jni
- 5. android jni чтение jobjectArray field failed
- 6. Вызов метода Java из JNI
- 7. Вызов метода WebView из JNI
- 8. Вызов с чистого метода c методу JNI
- 9. Вызов метода Java с помощью JNI
- 10. Как получить доступ к элементам из jobjectarray в jni
- 11. JNI вызов апи: получить идентификатор метода для метода с несколькими параметрами
- 12. Вызов метода модели с параметрами в Rails
- 13. Вызов метода с параметрами в другом методе
- 14. Вызов метода с параметрами в AppDelegate
- 15. JNI native dll не возвращает jobjectArray сбой VM
- 16. вызов метода с параметрами с помощью tkinter
- 17. jni: вызов метода java в его потоке
- 18. jni - конвертировать int [] [] в jobjectArray и возвращать его в java
- 19. Вызов метода из другого класса с параметрами
- 20. Вызов метода с необязательными параметрами из строки
- 21. Вызов метода Ruby с параметрами, разделенными пробелом
- 22. Как исправить JNI-крах на env-> NewObject?
- 23. Конфликтующие типы для метода с использованием jni?
- 24. Вызов основного метода из JNI не удается
- 25. JNI «NewObject» не возвращает NULL при инициализации его значением NULL?
- 26. вызов метода с параметрами, полученными из общего метода
- 27. Вызов метода с параметрами ref или out из анонимного метода
- 28. вызов главного метода в java-модуле с использованием JNI
- 29. C-JNI возвращает 2D int массив как JobjectArray
- 30. Как исправить JNI crash на env-> NewObject()?
Вы считали использование нескольких аргументов, а не только одного массива? Это упростит ситуацию. – tbodt
"call a constructor": вы имеете в виду конструктор java? И как вы находите подходящего конструктора, глядя на соответствующую подпись? – Christophe
Я не знаю, сколько аргументов будет принимать конструктор до вызова метода. – popgalop