2019-01-10 c调用jar包填坑记录

2019-01-10  本文已影响0人  oracle3

折腾了两天总算搞定c调用jar包,其中遇到的问题这里总结一下:
1、起始demo
参考C调用java例子先跑起来
2、开发环境
使用linux虚拟机效率很低,找到了gnuwin32实现在windows下运行Makefile,使用的是https://sourceforge.net/projects/gnuwin32/ ,只需要把 mingw32-make.exe文件改名为make.exe
3、java开发
直接使用eclipse生成一个mvn项目,以这个最简项目开始入手
使用mvn编译出jar给c调用,参考maven将所有的依赖打成一个包,确保依赖没有问题,验证方法:

java -cp mytest.jar com.test.mytest.App

能够执行成功(jar复制到c文件同一个目录,不成功估计是第7条的问题)
4、jar的调用
options.optionString ="-Djava.class.path=.;mytest.jar";
这个参数里面的分号不能搞错,否则总是找不到java的类
5、java函数返回值只能是string
其他类型一定得不到返回值,只好老老实实把其他类型转换为string返回
6、java函数执行异常返回值也拿不到
好的习惯是给java代码增加try catch,并且打印异常错误,从而能够快速发现问题,否则就是干着急也看不出问题在哪里,5和6两个问题基本耗费了我一天时间才解决
7、jvm.dll找不到的问题
直接把jvm.dll所在的路径添加到path就可以了
8、如果异常出现并显示java的crash堆栈
估计是函数的参数传递错误了,或者少传参数了
9、linux下和windows的区别有两个
编译命令要改一下:

gcc -I/usr/lib/jvm/jdk1.8.0_111/include -I/usr/lib/jvm/jdk1.8.0_111/include/linux -o hello_world hello_world.c -L/usr/lib/jvm/jdk1.8.0_111/jre/lib/amd64/server -ljvm -D__int64="long long" 

另外c代码里面改一句话

options.optionString ="-Djava.class.path=.;mytest.jar";

修改为:

options.optionString ="-Djava.class.path=.:mytest.jar";

这里附上c的代码,java代码就自己脑补

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include<jni.h>

JNIEnv* create_vm(JavaVM **jvm)
{
    JNIEnv* env;
    JavaVMInitArgs args;
    JavaVMOption options;
    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    options.optionString ="-Djava.class.path=.;mytest.jar";
    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 clazz;
    jmethodID main_method;
    jmethodID square_method;
    jmethodID power_method;
    jint number=20;
    jint exponent=3;
    clazz =(*env)->FindClass(env, "com/test/mytest/App");
    if(clazz == NULL) {
        printf("can't find hello_world_class");
        return;
    }
    // 这里调用main
    main_method =(*env)->GetStaticMethodID(env, clazz, "main","([Ljava/lang/String;)V");
    if(main_method == NULL) {
        printf("can't find main_method\n");
        return;
    }
    (*env)->CallStaticVoidMethod(env,clazz, main_method, NULL);

    // 这里调用public static String abiEncode(String abi, String data)
    jstring str = (*env)->NewStringUTF(env,"{ \"constant\":false,  \"inputs\":[{\"name\":\"i\",\"type\":\"int\"},  {\"name\":\"s\",\"type\":\"string\"},  {\"name\":\"j\",\"type\":\"int\"}],  \"name\":\"f4\",  \"outputs\":[{\"name\":\"i\",\"type\":\"int\"},  {\"name\":\"s\",\"type\":\"string\"},  {\"name\":\"j\",\"type\":\"int\"}],  \"type\":\"fallback\" }");
    printf("jstring str\n");

        jstring str2 = (*env)->NewStringUTF(env,"111, \"aaa\", 222");
    printf("jstring str2\n");

    jmethodID abiEncode_method =
    (*env)->GetStaticMethodID(env, clazz, "abiEncode","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

    if (abiEncode_method == NULL) {
        printf("can't find abiEncode_method\n");
        return; /* method not found */
    }


    jstring result = (*env)->CallStaticObjectMethod(env, clazz, abiEncode_method,str,str2);
    printf("jbyteArray arr %x\n",result);
    if (result == NULL) {
        printf("can't call abiEncode_method\n");
        return; /* method not found */
    }
    const char *message = (*env)->GetStringUTFChars(env, result, NULL);
    if (NULL == message) return;
    printf("In C, the returned string is %s\n", message);
    (*env)->ReleaseStringUTFChars(env, result, message);

        (*env)->DeleteLocalRef(env,str2);
        (*env)->DeleteLocalRef(env,str);
        (*env)->DeleteLocalRef(env,clazz);
        
}


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

如果不用Makefile就直接用下面的命令编译:

gcc -I"C:/Program Files/Java/jdk1.8.0_101/include/" -I"C:/Program Files/Java/jdk1.8.0_101/include/win32" -o hello_world hello_world.c -L"C:/Program Files/Java/jdk1.8.0_101/jre/bin/server" -ljvm -D__int64="long long"
上一篇 下一篇

猜你喜欢

热点阅读