处女贴:linux下通过JNI用C/C++中调用JAVA类,java类添加依赖包后,c++无法调用,无法找到class

时间:2022-09-30 13:43:18
案例原帖 http://blog.sina.com.cn/s/blog_48eef8410100fjxr.html

照着这样的例子下来是可以调用的,但import一个简单依赖包后就无法调用了,cpp代码如下

#include <stdio.h>
#include <iostream>
#include <jni.h>
#include <stdlib.h>
#include <assert.h>
#include <cstring>
 

jstring stoJstring(JNIEnv* env, const char* pat)
{
  jclass strClass = env->FindClass("java/lang/String");
  jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
  jbyteArray bytes = env->NewByteArray(strlen(pat));
  env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
  jstring encoding = env->NewStringUTF("utf-8");
  return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}
 

char* jstringTostring(JNIEnv* env, jstring jstr)
{
 char* rtn = NULL;
 jclass clsstring = env->FindClass("java/lang/String");
 jstring strencode = env->NewStringUTF("utf-8");
 jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
 jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
 jsize alen = env->GetArrayLength(barr);
 jbyte* ba = env->GetByteArrayElements(barr,JNI_FALSE);
 if(alen > 0){
  rtn = (char*)malloc(alen + 1);
  memcpy(rtn, ba, alen);
  rtn[alen] = 0;
 }
 env->ReleaseByteArrayElements(barr, ba, 0);
 return rtn;
}
 
using namespace std;
 
int main()
{
 JavaVMOption options[2];
 JNIEnv *env;
 JavaVM *jvm;
 JavaVMInitArgs vm_args;
 long status;
 jclass cls;
 jmethodID mid;
 jint square;
 jboolean jnot;
 jobject jobj;
 options[0].optionString = "-Djava.compiler=NONE";
 options[1].optionString = "-Djava.class.path=./;/home/grid/app/Test/lib/test.jar";
 cout<<options[1].optionString<<endl;
 //options[2].optionString = "-verbose:jni"; 用于跟踪运行时的信息
 vm_args.version = JNI_VERSION_1_4; // JDK版本号
 vm_args.nOptions = 2;
 vm_args.options = options;
 vm_args.ignoreUnrecognized = JNI_TRUE;
 status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

 if(status != JNI_ERR){
  printf("create java jvm success\n");
  cls = env->FindClass("com/test/MyTest");  // 在这里查找ava类
  if(cls !=0){
   printf("find java class success\n");
   // 构造函数
   mid = env->GetMethodID(cls,"<init>","(II)I");
   if(mid !=0){
    jobj=env->NewObject(cls,mid);
    std::cout << "init ok" << std::endl;
   }
       
   // 调用add函数
   mid = env->GetStaticMethodID( cls, "add", "(II)I");
   if(mid !=0){
    square = env->CallStaticIntMethod( cls, mid, 5,5);
    std::cout << square << std::endl;
   }
   

   // 调用judge函数
  }
  else{
   fprintf(stderr, "FindClass failed\n");
  }
 
  jvm->DestroyJavaVM();
  fprintf(stdout, "Java VM destory.\n");
  return 0;
 }
 else{
  printf("create java jvm fail\n");
  return -1;
 }
}



Mytest.java
package com.test;

import rtest.Test;

public class Mytest {

static Test sb = new Test();

public static int add(int a, int b) {
return sb.ad(a, b) + a + b;
}

public boolean judge(boolean bool) {
return !bool;
}

public static void main(String[] args) {
System.out.println(add(5, 5));
}
}



Test.java
package rtest;

public class Test {

public int ad(int a, int b) {
return a + b;
}

}


java独立运行是成功的
c++调用就提示FindClass failed
在网上找了好多答案都是说启动参数要加上依赖包路径,可我加了还是一样
 options[1].optionString = "-Djava.class.path=./;/home/grid/app/Test/lib/test.jar";

跪求大侠解答,在线等

11 个解决方案

#1


该回复于2014-11-26 10:30:17被管理员删除

#2


不要做A语言代码修改为B语言代码的无用功。
也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。
只需让A、B语言代码的输入输出重定向到文本文件,或修改A、B语言代码让其通过文本文件输入输出。
即可很方便地让A、B两种语言之间协调工作。
比如:
A将请求数据写到文件a.txt,写完后改名为aa.txt
B发现aa.txt存在时,读取其内容,调用相应功能,将结果写到文件b.txt,写完后删除aa.txt,改名为bb.txt
A发现bb.txt存在时,读取其内容,读完后删除bb.txt
以上A可以替换为任何一种开发语言或开发环境,B可以替换为任何一种与A不同的开发语言或开发环境。
除非A或B不支持判断文件是否存在、文件读写和文件更名。
但是谁又能举出不支持判断文件是否存在、文件读写和文件更名的开发语言或开发环境呢?

共享临时文本文件这种进程之间的通讯方法相比其它方法的优点有很多,下面仅列出我现在能想到的:
·进程之间松耦合
·进程可在同一台机器上,也可跨机,跨操作系统,跨硬件平台,甚至跨国。
·方便调试和监视,只需让第三方或人工查看该临时文本文件即可。
·方便在线开关服务,只需删除或创建该临时文本文件即可。
·方便实现分布式和负载均衡。
·方便队列化提供服务,而且几乎不可能发生队列满的情况(除非硬盘空间满)
·……

#3


如果对响应速度要求较高,读写文件就显得很慢了

#4


处女贴:linux下通过JNI用C/C++中调用JAVA类,java类添加依赖包后,c++无法调用,无法找到class
一般这种结构的API。。当你if(status != JNI_ERR){的时候,你可以getLastError看看到底是什么原因。一般会提示说缺了什么依赖的
楼主根据你的情况分析,你缺的依赖应该不仅仅是test.jar啊,应该还有其他的。比如“System.out.println”这个就需要io包了,但是没看到你指向jdk的路径

#5


引用 4 楼 sniffer12345 的回复:
处女贴:linux下通过JNI用C/C++中调用JAVA类,java类添加依赖包后,c++无法调用,无法找到class
一般这种结构的API。。当你if(status != JNI_ERR){的时候,你可以getLastError看看到底是什么原因。一般会提示说缺了什么依赖的
楼主根据你的情况分析,你缺的依赖应该不仅仅是test.jar啊,应该还有其他的。比如“System.out.println”这个就需要io包了,但是没看到你指向jdk的路径


曾将jdk的classpath加了进去也不奏效
谢谢这位大侠回复,没用过getLastError,先研究下

#6


该回复于2014-11-26 10:30:02被管理员删除

#7


该回复于2014-11-26 10:30:30被管理员删除

#8


该回复于2014-11-26 09:56:34被管理员删除

#9


该回复于2014-11-26 10:32:32被管理员删除

#10


 options[1].optionString = "-Djava.class.path=./;/home/grid/app/Test/lib/test.jar";
他妈的这里是用冒号分隔的你用分号???

#11


引用 10 楼 xiaoS999 的回复:
 options[1].optionString = "-Djava.class.path=./;/home/grid/app/Test/lib/test.jar";
他妈的这里是用冒号分隔的你用分号???


卧槽大神啊,解决了困扰我多年的便秘。。

#1


该回复于2014-11-26 10:30:17被管理员删除

#2


不要做A语言代码修改为B语言代码的无用功。
也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。
只需让A、B语言代码的输入输出重定向到文本文件,或修改A、B语言代码让其通过文本文件输入输出。
即可很方便地让A、B两种语言之间协调工作。
比如:
A将请求数据写到文件a.txt,写完后改名为aa.txt
B发现aa.txt存在时,读取其内容,调用相应功能,将结果写到文件b.txt,写完后删除aa.txt,改名为bb.txt
A发现bb.txt存在时,读取其内容,读完后删除bb.txt
以上A可以替换为任何一种开发语言或开发环境,B可以替换为任何一种与A不同的开发语言或开发环境。
除非A或B不支持判断文件是否存在、文件读写和文件更名。
但是谁又能举出不支持判断文件是否存在、文件读写和文件更名的开发语言或开发环境呢?

共享临时文本文件这种进程之间的通讯方法相比其它方法的优点有很多,下面仅列出我现在能想到的:
·进程之间松耦合
·进程可在同一台机器上,也可跨机,跨操作系统,跨硬件平台,甚至跨国。
·方便调试和监视,只需让第三方或人工查看该临时文本文件即可。
·方便在线开关服务,只需删除或创建该临时文本文件即可。
·方便实现分布式和负载均衡。
·方便队列化提供服务,而且几乎不可能发生队列满的情况(除非硬盘空间满)
·……

#3


如果对响应速度要求较高,读写文件就显得很慢了

#4


处女贴:linux下通过JNI用C/C++中调用JAVA类,java类添加依赖包后,c++无法调用,无法找到class
一般这种结构的API。。当你if(status != JNI_ERR){的时候,你可以getLastError看看到底是什么原因。一般会提示说缺了什么依赖的
楼主根据你的情况分析,你缺的依赖应该不仅仅是test.jar啊,应该还有其他的。比如“System.out.println”这个就需要io包了,但是没看到你指向jdk的路径

#5


引用 4 楼 sniffer12345 的回复:
处女贴:linux下通过JNI用C/C++中调用JAVA类,java类添加依赖包后,c++无法调用,无法找到class
一般这种结构的API。。当你if(status != JNI_ERR){的时候,你可以getLastError看看到底是什么原因。一般会提示说缺了什么依赖的
楼主根据你的情况分析,你缺的依赖应该不仅仅是test.jar啊,应该还有其他的。比如“System.out.println”这个就需要io包了,但是没看到你指向jdk的路径


曾将jdk的classpath加了进去也不奏效
谢谢这位大侠回复,没用过getLastError,先研究下

#6


该回复于2014-11-26 10:30:02被管理员删除

#7


该回复于2014-11-26 10:30:30被管理员删除

#8


该回复于2014-11-26 09:56:34被管理员删除

#9


该回复于2014-11-26 10:32:32被管理员删除

#10


 options[1].optionString = "-Djava.class.path=./;/home/grid/app/Test/lib/test.jar";
他妈的这里是用冒号分隔的你用分号???

#11


引用 10 楼 xiaoS999 的回复:
 options[1].optionString = "-Djava.class.path=./;/home/grid/app/Test/lib/test.jar";
他妈的这里是用冒号分隔的你用分号???


卧槽大神啊,解决了困扰我多年的便秘。。