JNI / JNA 不满足 Link,但存在符号

JNI / JNA Unsatisfied Link, but symbol is present

我正在尝试通过提供的 c 库 "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 and/or 本机 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");
    }
}

我错过了什么?

@更新:

我现在将 JNI class 和 JNA 接口移到了正确的包中并重命名了 jna 接口

包 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.

只要完全限定的class名称等于本机库中定义的名称,JNI 方法就会起作用

如果问题是“为什么我不能用 JNA 调用 JNI 方法?”:

为了能够从 Java 调用外部库,您必须使用 JNI。您将一些方法声明为 native 并且 javah 将为您生成特殊函数,您可以用您的代码填充这些函数。每个函数都有两个附加参数:绑定到调用 Java 线程的 env 指针和作为方法接收器的对象或 class。如果您将 Java 对象作为其他参数之一传递,您将在函数中获得 jobject

如果 JNI 函数的实现只包括将调用转发到另一个外部库,您也可以使用 JNA。 JNA 使用 JNI 包装 libffi 因此您可以直接调用现有的外部库。这样您就不必自己创建包装库。 JNA 不会创建 env 指针或将方法接收器作为参数传递。它将尝试将所有其他参数编组为外部库可以理解的内容。这意味着这里没有 jobject

总结:JNI 调用为其显式创建的函数并且参数是 Java 特定的。 JNA 在内部使用 JNI 来调用 non-Java 个外部库中的函数。