i am trying to integrate a legacy system via a provided c-library "libext.so". To test JNA/JNI i want to call the "setProperty" function.
objdump libext.so -t | grep setProperty
0000000000104d50 g F .text 000000000000000e Java_ExtClass_setProperty
0000000000104be0 g F .text 000000000000016a Java_com_company_ExtClass_setProperty
this is my code, using java 8, jna 4.5.1 and/or native jni, both ways fail with an UnsatisfiedLinkError
when calling the function - loading the library works without an Exception.
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");
}
}
what am i missing?
@Update:
I now moved both, the JNI class and the JNA INterface to the correct package and renamed the jna interface
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);
}
calling the first two methods on INSTANCE gives an InvalidMemoryAccess
, the second two an UnsatisfiedLinkError
.
The JNI Method worked, as soon as the fully qualified classname was equal to the one defined in the native library
If the question is "why can't I call JNI methods with JNA?":
To be able to call external libraries from Java you have to use JNI. You declare some methods as native
and javah
will generate special functions for you that you can fill in with your code. Every function will have two additional arguments: an env
pointer that is bound to the calling Java thread and the object or class that is the method receiver. If you pass a Java object as one of the other arguments you will get a jobject
in your function.
If the implementation of the JNI functions would only consist of forwarding the calls to another external library you can also use JNA. JNA uses JNI to wrap libffi so you can call an existing external library directly. This way you don't have to create a wrapper library yourself. JNA will not create an env
pointer or pass the method receiver as argument. And it will try to marshal all the other arguments into something the external library understands. That means no jobject
s here.
Summary: JNI calls functions explicitly created for it and the arguments are Java specific. JNA uses JNI internally to call functions in non-Java external libraries.