JNI java.lang.UnsatisfiedLinkError

2 篇文章 0 订阅

使用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版本:告诉VM该组件使用那一个JNI版本(若未提供 JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。
  • 初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当,RegisterNatives也在这里进行。

JNI_OnUnload()当VM释放该组件时被调用,JNI_OnUnload()函数的作用与JNI_OnLoad()对应,因此在该方法中进行善后清理,资源释放的动作最为合适。


我的代码示例如下, 见JNI_OnLoad:


#include <iostream>
//#include "JSegJNI.h"
#include <jni.h>
#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<Token> & result){
    jclass list_cls = env->FindClass("Ljava/util/ArrayList;");//获得ArrayList类引用
    jmethodID list_costruct = env->GetMethodID(list_cls , "<init>","()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 , "<init>", "(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<Token> 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<Token> 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<Token> 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<Token> 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<Token> 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:"<<p<<endl;
    vector<Token> result;
    GetTokenizer().maxSplit(Utf8ToUnicode(p), result);
    env->ReleaseStringUTFChars(jstr, p);
    for(int i = 0; i< result.size(); i++){
        cout<<"("<<result[i]._off<<","<<result[i]._len<<")";
    }
}
static JNINativeMethod s_methods[] = {
    {"MaxSplit", "(Ljava/lang/String;)Ljava/util/List;", (void*)Java_com_mingspy_jseg_JSegJNI_MaxSplit},
    {"FullSplit", "(Ljava/lang/String;)Ljava/util/List;", (void*)Java_com_mingspy_jseg_JSegJNI_FullSplit},
    {"UniGramSplit", "(Ljava/lang/String;)Ljava/util/List;", (void*)Java_com_mingspy_jseg_JSegJNI_UniGramSplit},
    {"BiGramSplit", "(Ljava/lang/String;)Ljava/util/List;", (void*)Java_com_mingspy_jseg_JSegJNI_BiGramSplit},
    {"MixSplit", "(Ljava/lang/String;)Ljava/util/List;", (void*)Java_com_mingspy_jseg_JSegJNI_MixSplit},
};
JNIEXPORT jint JNICALL
    JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JNIEnv* env = NULL;
    if (vm->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;
}



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值