我正在尝试通过提供的c-library“libext.so”集成遗留系统。 为了测试JNA / JNI,我想调用“setProperty”函数。
objdump libext.so -t | grep setProperty
0000000000104d50 g F .text 000000000000000e Java_ExtClass_setProperty
0000000000104be0 g F .text 000000000000016a Java_com_company_ExtClass_setProperty
这是我的代码,使用java 8,jna 4.5.1和/或native jni,在调用函数时两种方式都失败了UnsatisfiedLinkError
- 加载库没有异常。
public class TestClass
{
static {
try {
System.load("/path/to/libext.so");
} catch (Throwable e) {
e.printStackTrace();
}
}
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary(("/path/to/libext.so"), CLibrary.class);
void setProperty(String key, String value);
}
public static native synchronized void setProperty(String key, String value);
public static void main(String[] args) {
// setProperty("a", "b");
CLibrary.INSTANCE.setProperty("a", "b");
}
}
我错过了什么?
@Update:
我现在将JNI类和JNA INterface都移动到正确的包并重命名为jna接口
package com.company;
public interface LibExtLibrary extends Library {
LibExtLibrary INSTANCE = (LibExtLibrary)
Native.loadLibrary(("/path/to/libext.so"),
LibExtLibrary.class);
void Java_com_company_ExtClass_setProperty(String key, String value);
void Java_ExtClass_setProperty(String key, String value);
void ExtClass_setProperty(String key, String value);
void setProperty(String key, String value);
}
在INSTANCE上调用前两个方法会产生InvalidMemoryAccess
,后两个方法会产生UnsatisfiedLinkError
。
只要完全限定的类名等于本机库中定义的类名,JNI方法就可以工作
答案 0 :(得分:1)
如果问题是"为什么我不能用JNA调用JNI方法?":
为了能够从Java调用外部库,您必须使用JNI。您将某些方法声明为native
,javah
将为您生成可以填写代码的特殊函数。每个函数都有两个额外的参数:绑定到调用Java线程的env
指针和作为方法接收器的对象或类。如果您将Java对象作为其他参数之一传递,您将在函数中获得jobject
。
如果JNI函数的实现只包括将调用转发到另一个外部库,您也可以使用JNA。 JNA 使用 JNI来包装libffi,以便您可以直接调用现有的外部库。这样您就不必自己创建包装库。 JNA不会创建env
指针或将方法接收器作为参数传递。它会尝试将所有其他参数整理成外部库理解的东西。这意味着此处没有jobject
。
总结:JNI调用为其显式创建的函数,参数是Java特定的。 JNA在内部使用JNI来调用非Java外部库中的函数。