Требует ли JNI упорядочения аргументов на основе типов аргументов?

Я пытаюсь интегрировать некоторый код JNI в свое приложение, которое получает данные от веб-службы и анализирует их на уровне JNI. Я пытаюсь вызвать метод, определенный на уровне Java, передав некоторые аргументы, полученные от веб-службы. Ниже приведен поток функций и методов:

Переменные, определенные для jclass и jmethodID:

    static jclass userInfo                      = NULL ;
    static jmethodID create_user_info = NULL ;

Структура, определенная на уровне c для хранения значений

    struct User_Info {            
        long userId; // 1
        std::string firstName; // 2
        std::string lastName; // 3
        bool follow; // 4
    };

У этой функции есть проблема. Эта функция вызывается после получения данных от веб-сервиса, их разбора и создания структуры User_Info.

    static jobject createJavaObject(JNIEnv *env, const User_Info& info) {
        if(!userInfo){
            userInfo = (jclass)env->NewGlobalRef(env->FindClass("com/model/UserInfo"));
            assert(userInfo != NULL);
            create_user_info = env->GetStaticMethodID(userInfo, "createUserInfo", "("
                "I" // userId // 1
                "Ljava/lang/String;" // firstName // 2
                "Ljava/lang/String;" // lastName // 3
                "Z" // follow // 4
                ")Lcom/model/UserInfo;");
            assert(create_user_info != 0);
        }
        jstring firstName = cast<jstring>(env, info.first_name); // cast function just converts string to jstring 
        assert(firstName != NULL);
        jstring lastName = cast<jstring>(env, info.last_name);  // cast function just converts string to jstring 
        assert(lastName != NULL);
        
        // ISSUE IS WITH FOLLOWING CALL
        jobject res = env->CallStaticObjectMethod(userInfo, create_user_info,
                                                                  info.userId, // 1
                                                                  firstName, // 2
                                                                  lastName, // 3
                                                                  info.follow // 4 
                                                                  );

        env->DeleteLocalRef(firstName);
        env->DeleteLocalRef(lastName);
        return res;
    }
    
    
    // cast function:
    
    jstring cast<jstring, char const *>()(JNIEnv *env, char const *s)         {
        if (!s) return 0;
        jbyteArray bytes = env->NewByteArray(strlen(s));
        env->SetByteArrayRegion(bytes, 0, strlen(s), (jbyte*)s);
        jmethodID midStringCtor = env->GetMethodID(clsString, "<init>", "([BLjava/lang/String;)V");
        jstring ret = (jstring)env->NewObject(clsString, midStringCtor, bytes, encoding);
        env->DeleteLocalRef(bytes);
        return ret;
    }
    

Java-метод:

@Native
private static UserInfo createUserInfo(
                            int userId, // 1
                            String firstname, // 2
                            String lastname, // 3
                            boolean follow // 4
                        ) {
    UserInfo info = new UserInfo();
    info.userId = userId;
    info.firstname = firstname;
    info.lastname = lastname;
    info.follow = follow;
    return info;
}   

Проблема в том, что когда я запускаю код, я получаю следующую ошибку:

ОШИБКА JNI (ошибка приложения): ожидается jboolean (0/1), но получено значение 1048605 в качестве аргумента 4 для com.model.UserInfo com.model.UserInfo.createUserInfo(int, java.lang.String, java.lang.String, логическое значение)

Когда я меняю порядок аргументов в методе java и функциях jni и сохраняю логическое значение «follow» сразу после int «userId», проблема не возникает.

Мой вопрос:

Требует ли JNI упорядочения аргументов на основе их типов, например. параметр int перед long/boolean или примитивные параметры перед объектами и т. д.

Если да, есть ли какие-либо ссылки/документы, которые предлагают это, если нет, то почему мой код работает после изменения порядка аргументов?


person Suresh Pal    schedule 23.08.2016    source источник
comment
Подсказка: если вы на 100% уверены, что ваш ввод из веб-сервиса в порядке, тогда: почему вы говорите об этом здесь? Я имею в виду следующее: постарайтесь свести свой вопрос к абсолютному минимуму. Вещи, которые происходят до/после проблемного кода, но не имеют никакого отношения к самой проблеме, в этом смысле просто бесполезны — простое упоминание заставляет людей задуматься об этом; что ничуть не помогает (я не говорю, что вы написали плохой вопрос, просто указываю, что минимализм помогает получить хорошие ответы).   -  person GhostCat    schedule 23.08.2016
comment
И примечание: когда речь идет о структурах, всегда возникает вопрос, как они упакованы/выровнены. Если я правильно помню, если вы не укажете такие вещи, компилятор может делать то, что он хочет. Другими словами: возможно, компилятор просто решил поместить логическое значение в качестве второго элемента; и, таким образом, компилятор C++ неявно определяет нужный вам порядок.   -  person GhostCat    schedule 23.08.2016
comment
1. Да, я на 100% уверен в вебсервисе. Это может быть неактуально для этого вопроса. Если это необходимо, я обновлю свой вопрос. 2. Что касается структуры, как я уже упоминал, я только начал с С++, я понятия не имею, как конкретно сообщить компилятору, чтобы он принимал значения структуры в том же порядке, что и определено. Если вы можете предоставить больше информации об этом, я могу попробовать на своей стороне и посмотреть, работает ли он или нет.   -  person Suresh Pal    schedule 23.08.2016
comment
Для GCC (и, возможно, Clang) вы бы сказали struct __attribute__ ((__packed__)) User_Info { blah blah };   -  person Michael    schedule 23.08.2016
comment
Я не думаю, что передача bool С++ напрямую в JNI - хорошая идея. Вы пробовали info.follow ? JNI_TRUE : JNI_FALSE?   -  person user2543253    schedule 23.08.2016
comment
Чтобы ответить на ваш вопрос: нет.   -  person samgak    schedule 23.08.2016
comment
@Michael: я попытался изменить определение структуры, как вы предложили. Тем не менее проблема сохраняется.   -  person Suresh Pal    schedule 23.08.2016
comment
@ user2543253: Да, я пробовал синтаксис выше. Даже я пытался передать JNI_FALSE/JNI_TRUE/0/1/и т. д., во всех случаях присутствовала одна и та же ошибка. Единственный сценарий его работы - это когда я перехожу чуть ниже к userId, следующим образом: / firstName // 2 Ljava/lang/String; // lastName // 3 )Lcom/model/UserInfo;); Я меняю порядок в функциях jni и методах java. Таким образом, порядок такой же, как указано выше, во всех местах, и он работает.   -  person Suresh Pal    schedule 23.08.2016
comment
Не знаю, как Android отреагирует на это, но может ли быть так, что стек запутался, поместив (я предполагаю, 64-битный) long там, где ожидается (32-битный) jint? Компилятор не может обнаружить это из-за varargs. Вы пытались явно привести userId к jint?   -  person user2543253    schedule 23.08.2016


Ответы (1)


Требуется ли сохранять некоторый порядок примитивов и объектов в аргументах функции JNI

Этот вопрос едва ли можно понять. Что требуется, так это поддерживать объявление метода метода JNI в соответствии с тем, что получается при запуске javah в классе, содержащем собственные методы.

static jclass userInfo                      = NULL ;

Вот ошибка. Недопустимо сохранять статические ссылки на jobjects или jclasses, если только они не являются глобальными или слабыми ссылками.

person user207421    schedule 23.08.2016
comment
Обновил мой вопрос. Во-вторых, я думаю, что код правильный. Эта ссылка используется только для вызова метода java. Проверка уже есть, если она еще не инициализирована. Так что каждый раз будет только одна ссылка - person Suresh Pal; 23.08.2016
comment
Код неверный по указанной мной причине. См. обсуждение глобальных ссылок в Спецификации JNI. Переменная jclass не может быть статической. - person user207421; 23.08.2016