JNI代码返回字符串,但出现错误java.lang.UnsatisfiedLinkError:com.package.openGeoDb()Ljava / lang / String;

时间:2019-04-01 07:54:29

标签: java c++ java-native-interface

我正在部署程序,遇到

错误
Caused by: java.lang.Exception: java.lang.UnsatisfiedLinkError: 
com.package.JniClass.JniGeoDbReader.openGeoDb()Ljava/lang/String;

我设法加载了dll,但我感觉是某些原因导致了字符串无法正确转换并导致了错误。以下是我目前正在测试以部署在Karaf上的JNI代码:

JNI代码>>> JAVA和c ++

JniGeoDbReader.class

package com.package.JniClass;

public final class JniGeoDbReader {

private JniGeoDbReader() { }

public static native String openGeoDb(); }

ServiceClass.class <---此类是简化版本

import com.package.JniClass.JniGeoDbReader;

public class ServiceClass{
  public void fetchResponse(){    
    System.load("D:\\DLL_PATH\\com_package_jniGeoDbReader.dll");
    LOGGER.info(">>>>>>>>>>>>>>>>> {}", JniGeoDbReader.openGeoDb());
  }
}

com_package_JniClass_JniGeoDbReader.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_package_JniClass_JniGeoDbReader */

#ifndef _Included_com_package_JniClass_JniGeoDbReader
#define 
_Included_com_package_JniClass_JniGeoDbReader_JniClass_JniGeoDbReader
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_package_JniClass_JniGeoDbReader
 * Method:    openGeoDb
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL 
 Java_com_package_JniClass_JniGeoDbReader_openGeoDb
(JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

dllmain.cpp <-我从其他地方获得了这段代码

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "com_package_JniClass_JniGeoDbReader.h"
#include <string>

using namespace std;

BOOL APIENTRY DllMain( HMODULE hModule,
                   DWORD  ul_reason_for_call,
                   LPVOID lpReserved
                 )
{
  switch (ul_reason_for_call)
  {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
      break;
  }
  return TRUE;
}

JNIEXPORT jstring JNICALL 
Java_com_package_JniClass_JniGeoDbReader_openGeoDb
(JNIEnv *env , jobject obj) {
   string message = "Welcome to JNI";
   int byteCount = message.length();
   const jbyte* pNativeMessage = reinterpret_cast<const jbyte*> 
       (message.c_str());
   jbyteArray bytes = env->NewByteArray(byteCount);
   env->SetByteArrayRegion(bytes, 0, byteCount, pNativeMessage);

   // find the Charset.forName method:
   //   javap -s java.nio.charset.Charset | egrep -A2 "forName"
   jclass charsetClass = env->FindClass("java/nio/charset/Charset");
   jmethodID forName = env->GetStaticMethodID(
    charsetClass, "forName", " 
      (Ljava/lang/String;)Ljava/nio/charset/Charset;");
   jstring utf8 = env->NewStringUTF("UTF-8");
   jobject charset = env->CallStaticObjectMethod(charsetClass, 
      forName, utf8);

  // find a String constructor that takes a Charset:
  //   javap -s java.lang.String | egrep -A2 "String\(.*charset"
   jclass stringClass = env->FindClass("java/lang/String");
   jmethodID ctor = env->GetMethodID(
    stringClass, "<init>", "([BLjava/nio/charset/Charset;)V");

   jstring jMessage = reinterpret_cast<jstring>(
    env->NewObject(stringClass, ctor, bytes, charset));
   return jMessage; }

我从以下位置在cpp中获得了代码:Send C++ string to Java via JNI。我想做类似的事情,即返回一个字符串而不接受任何参数。但是由于某种原因,它会引发错误。请指导我导致此错误的原因以及应该更改此代码的哪一部分。谢谢。

更新

这是完整的堆栈跟踪:

    at com.sun.proxy.$Proxy116.fetchCatalogue(Unknown Source)
    at com.package.ArcGisDiscoveryJob$CatalogueTask.call(ArcGisDiscoveryJob.java:485)
    at com.package.ArcGisDiscoveryJob$CatalogueTask.call(ArcGisDiscoveryJob.java:450)
    at com.package.BaseTaskExecutor.invoke(BaseTaskExecutor.java:84)
    at com.package.ArcGisDiscoveryJob.traverse(ArcGisDiscoveryJob.java:131)
    at com.package.ArcGisDiscoveryJob.run(ArcGisDiscoveryJob.java:224)
    at com.package.BaseScheduler$1.run(BaseScheduler.java:101)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.Exception: java.lang.UnsatisfiedLinkError: com.package.JniClass.JniGeoDbReader.openGeoDb()Ljava/lang/String;
    at com.package.service.rest.impl.ArcGisClientProxy$1.call(ArcGisClientProxy.java:161)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    ... 3 more
Caused by: java.lang.UnsatisfiedLinkError: com.package.JniClass.JniGeoDbReader.openGeoDb()Ljava/lang/String;
    at com.package.JniClass.JniGeoDbReader.openGeoDb(Native Method)
    at com.package.service.rest.impl.ServiceClass.fetchResponse(ServiceClass.java:364)
    at com.package.service.rest.impl.ServiceClass.fetchCatalogue(ServiceClass.java:124)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.package.service.rest.impl.ArcGisClientProxy.callEndPoint(ArcGisClientProxy.java:241)
    at com.package.service.rest.impl.ArcGisClientProxy.access$000(ArcGisClientProxy.java:32)
    at com.package.service.rest.impl.ArcGisClientProxy$1.call(ArcGisClientProxy.java:155)
    ... 4 more

1 个答案:

答案 0 :(得分:0)

您的头文件和您的CPP代码不匹配。标头为第二个函数参数声明jclass,但是实现中有jobject。 JNI本身不会在乎,因为jclassjobject相同,但是由于参数声明不同,因此编译器将无法识别该函数。因此,它将看不到该功能的extern "C"并以CPP名称处理将其导出,而Java将找不到它。

编辑:没有看到@ user207421的注释,并且很重要的一点是,如果您的本机方法发生更改,请务必重新生成头文件,但这对您无济于事,因为您的头已经与Java代码匹配。您还必须更改实现以匹配标题。