使用VS2010编译JNI,开始时Java端调用正常,加入几个函数后,怎么都无法调用了,报如下错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.mingspy.jseg.JSegJNI.MaxSplit(Ljava/lang/String;)Ljava/util/List;
在网上查询了一下,可能是jni端函数名字编译时,多了字符@,需要加参数。查询了不少文章,只是用于gcc的(如加入在linker flags处填入:-Wl,--add-stdcall-alias),唯独没有关于VS的。
最后采用RegisterNativeMethods解决。摘自网上的一段评论如下:
除了使用传统方法实现JNI外,也可以使用RegisterNatives实现JNI。和传统方法相比,使用RegisterNatives的好处有三点:
1、C++中函数命名自由,不必像javah自动生成的函数声明那样,拘泥特定的命名方式;
2、效率高。传统方式下,Java类call本地函数时,通常是依靠VM去动态寻找.so中的本地函数(因此它们才需要特定规则的命名格式),而使用RegisterNatives将本地函数向VM进行登记,可以让其更有效率的找到函数;
3、运行时动态调整本地函数与Java函数值之间的映射关系,只需要多次call RegisterNatives()方法,并传入不同的映射表参数即可。
为了使用RegisterNatives,我们需要了解JNI_OnLoad和JNI_OnUnload函数。JNI_OnLoad()函数在VM执行System.loadLibrary(xxx)函数时被调用,它有两个重要的作用:
JNI_OnUnload()当VM释放该组件时被调用,JNI_OnUnload()函数的作用与JNI_OnLoad()对应,因此在该方法中进行善后清理,资源释放的动作最为合适。
我的代码示例如下, 见JNI_OnLoad:
#include
//#include "JSegJNI.h"
#include
#include "AutoTokenizer.hpp"
#include "CodeUtils.hpp"
using namespace std;
using namespace mingspy;
static ITokenizer & GetTokenizer(){
static AutoTokenizer t;
return t;
}
static jobject toJavaList(JNIEnv * env, const vector & result){
jclass list_cls = env->FindClass("Ljava/util/ArrayList;");//获得ArrayList类引用
jmethodID list_costruct = env->GetMethodID(list_cls , "","()V"); //获得得构造函数Id
jmethodID list_add = env->GetMethodID(list_cls,"add","(Ljava/lang/Object;)Z");
jobject list_obj = env->NewObject(list_cls , list_costruct);
jclass token_cls = env->FindClass("Lcom/mingspy/jseg/Token;");
jmethodID token_costruct = env->GetMethodID(token_cls , "", "(II)V");
for(int i = 0 ; i < result.size(); i++)
{
jobject t_obj = env->NewObject(token_cls , token_costruct , result[i]._off,result[i]._len);
env->CallBooleanMethod(list_obj , list_add , t_obj);
}
return list_obj ;
}
/*
* Class: com_mingspy_jseg_JSegJNI
* Method: MaxSplit
* Signature: (Ljava/lang/String;)Ljava/util/List;
*/
jobject Java_com_mingspy_jseg_JSegJNI_MaxSplit
(JNIEnv * env, jobject obj, jstring jstr)
{
const char * p = env->GetStringUTFChars(jstr, 0);
vector result;
GetTokenizer().maxSplit(Utf8ToUnicode(p), result);
env->ReleaseStringUTFChars(jstr, p);
return toJavaList(env,result);
}
/*
* Class: com_mingspy_jseg_JSegJNI
* Method: FullSplit
* Signature: (Ljava/lang/String;)Ljava/util/List;
*/
jobject Java_com_mingspy_jseg_JSegJNI_FullSplit
(JNIEnv * env, jobject obj, jstring jstr)
{
const char * p = env->GetStringUTFChars(jstr, 0);
vector result;
GetTokenizer().fullSplit(Utf8ToUnicode(p), result);
env->ReleaseStringUTFChars(jstr, p);
return toJavaList(env,result);
}
/*
* Class: com_mingspy_jseg_JSegJNI
* Method: UniGramSplit
* Signature: (Ljava/lang/String;)Ljava/util/List;
*/
jobject Java_com_mingspy_jseg_JSegJNI_UniGramSplit
(JNIEnv * env, jobject obj, jstring jstr){
const char * p = env->GetStringUTFChars(jstr, 0);
vector result;
GetTokenizer().uniGramSplit(Utf8ToUnicode(p), result);
env->ReleaseStringUTFChars(jstr, p);
return toJavaList(env,result);
}
/*
* Class: com_mingspy_jseg_JSegJNI
* Method: BiGramSplit
* Signature: (Ljava/lang/String;)Ljava/util/List;
*/
jobject Java_com_mingspy_jseg_JSegJNI_BiGramSplit
(JNIEnv * env, jobject obj, jstring jstr){
const char * p = env->GetStringUTFChars(jstr, 0);
vector result;
GetTokenizer().biGramSplit(Utf8ToUnicode(p), result);
env->ReleaseStringUTFChars(jstr, p);
return toJavaList(env,result);
}
/*
* Class: com_mingspy_jseg_JSegJNI
* Method: MixSplit
* Signature: (Ljava/lang/String;)Ljava/util/List;
*/
jobject Java_com_mingspy_jseg_JSegJNI_MixSplit
(JNIEnv * env, jobject obj, jstring jstr)
{
const char * p = env->GetStringUTFChars(jstr, 0);
vector result;
GetTokenizer().mixSplit(Utf8ToUnicode(p), result);
env->ReleaseStringUTFChars(jstr, p);
return toJavaList(env,result);
}
/*
* Class: com_mingspy_jseg_JSegJNI
* Method: Test
* Signature: (Ljava/lang/String;)V
*/
void Java_com_mingspy_jseg_JSegJNI_Test
(JNIEnv * env, jobject obj, jstring jstr)
{
const char * p = env->GetStringUTFChars(jstr, 0);
cout<<"input is:"< result;
GetTokenizer().maxSplit(Utf8ToUnicode(p), result);
env->ReleaseStringUTFChars(jstr, p);
for(int i = 0; i< result.size(); i++){
cout<<"("<GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
{
return JNI_ERR;
}
jclass cls = env->FindClass("Lcom/mingspy/jseg/JSegJNI;");
if (cls == NULL)
{
return JNI_ERR;
}
int len = sizeof(s_methods) / sizeof(s_methods[0]);
if (env->RegisterNatives(cls, s_methods, len) < 0)
{
return JNI_ERR;
}
return JNI_VERSION_1_4;
}