JNI load jar с зависимостями

Я пытаюсь загрузить следующий класс java в свою программу на C ++ с помощью JNI:

package helloWorld;

import org.apache.log4j.Logger;

public class HelloWorld{

    private static final Logger logger = Logger.getLogger(HelloWorld.class);

    public static void main(String[] args){
        System.out.println("Hello, World");
    }
    public static int square(int input){
        int output = input * input;
        return output;
    }
    public static int power(int input, int exponent){
        int output,i;
        output=1;
        for(i=0;i<exponent;i++){
            output *= input;
        }
        return output;
    }
}

Это зависит от log4j-1.2.16.jar

Вот мой код на C ++:

#include <stdio.h>
#include <cstdlib>
#include "../Header/jni.h"

JNIEnv* create_vm(JavaVM **jvm)
{
    char * classPath = (char *) "-Djava.class.path=HelloWorld-0.0.1-SNAPSHOT.jar";
    JNIEnv* env;
    JavaVMInitArgs args;
    JavaVMOption options[2];
    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    options[0].optionString = classPath;
    options[1].optionString = "-verbose";
    args.options = options;
    args.ignoreUnrecognized = 0;
    int rv;
    rv = JNI_CreateJavaVM(jvm, (void**)&env, &args);
    if (rv < 0 || !env)
        printf("Unable to Launch JVM %d\n",rv);
    else
        printf("Launched JVM! :)\n");
    return env;
}

void invoke_class(JNIEnv* env)
{
    jclass hello_world_class;
    jmethodID main_method;
    jmethodID square_method;
    jmethodID power_method;
    jint number=20;
    jint exponent=3;

    hello_world_class = env->FindClass("helloWorld/HelloWorld");

    if(hello_world_class == NULL){
        if(env->ExceptionOccurred()){
            env->ExceptionDescribe();
        }
        printf("Class not found.");
    }
    else{
        main_method = env->GetStaticMethodID(hello_world_class, "main", "([Ljava/lang/String;)V");
        square_method = env->GetStaticMethodID(hello_world_class, "square", "(I)I");
        power_method = env->GetStaticMethodID(hello_world_class, "power", "(II)I");
        env->CallStaticVoidMethod(hello_world_class, main_method, NULL);
        printf("%d squared is %d\n", number,
                env->CallStaticIntMethod(hello_world_class, square_method, number));
        printf("%d raised to the %d power is %d\n", number, exponent,
                env->CallStaticIntMethod(hello_world_class, power_method, number, exponent));
    }
}

int main(int argc, char **argv)
{
    JavaVM *jvm;
    JNIEnv *env;
    env = create_vm(&jvm);
    if(env == NULL)
        return 1;
    invoke_class(env);
    system("PAUSE");
    return 0;
}

Я поместил HelloWorld.jar в корневую папку моего приложения C ++. Когда он пытается загрузить hello_world_class, выдается следующее исключение:

java.lang.NoClassDefFoundError: org/apache/log4j/Logger
    at helloWorld.HelloWorld.<clinit>(HelloWorld.java:7)

JNI не находит зависимость log4j, потому что она не находится внутри HelloWorld.jar. Я попытался поместить его в папку lib и в ту же папку, что и HelloWorld.jar, но это не сработало. Где мне нужно разместить файл log4j.jar, чтобы JNI мог его реорганизовать и загрузить?

Большое спасибо, я новичок в jni, поэтому, пожалуйста, будьте ясны в своих ответах. Я был на этой ошибке весь день T.T.


person Victor Silva Do Nascimento    schedule 16.10.2015    source источник
comment
Если это код C ++, почему вы пометили C?   -  person PC Luddite    schedule 16.10.2015
comment
Извините, удалил тег.   -  person Victor Silva Do Nascimento    schedule 16.10.2015
comment
Вы уже явно указываете часть класса; почему бы не перечислить оба jars?   -  person Alan Stokes    schedule 17.10.2015
comment
@AlanStokes, вы имеете в виду объявление другого classPath с путем к jar log4j? Но поймет ли jni, что это зависимость HelloWorld.jar? Как связать его как зависимость с HelloWorld?   -  person Victor Silva Do Nascimento    schedule 17.10.2015
comment
-Djava.class.path=foo.jar;baz.jar (Или используйте: нет; в Linux.) Он не заботится о зависимостях, он просто хочет знать, где искать каждый класс, когда он ему нужен.   -  person Alan Stokes    schedule 17.10.2015


Ответы (1)


Все, что вам нужно сделать, это указать расположение JAR файлов внутри параметров. Вы можете сделать что-то вроде этого:

options[0].optionString = "-Djava.class.path=./target:../target:./jar:./jar/log4j-api-2.12.1.jar:./jar/log4j-core-2.12.1.jar";

Помните, что вам, вероятно, также понадобится log4j2.xml (в случае log4j-2.12.1). Чтобы убедиться, что ваш файл конфигурации доступен для обнаружения, также добавьте каталог (с файлом) в путь к классу.

Вы можете найти полный образец кода здесь: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo060

person Oo.oO    schedule 18.09.2019