Reputation: 31
I need to access a "native" C library from Java via Java Native Access (JNA). The idiomatic way to do this seems to be defining an interface that extends Library
and that declares all the functions which I need to access. Then create a singleton instance, via Native.load()
method:
public interface MyLibrary extends Library {
MyLibrary INSTANCE = Native.load("mylib", MyLibrary.class);
int some_function(int param);
}
This works fine with functions. But how do I access global variables via the JNA interface?
In the C header file, it is defined like:
extern const uint16_t SOME_GLOBAL_VARIABLE;
There is little to no information available on how to access global variables via the JNA interface. The closest thing I have found is the NativeLibrary.getGlobalVariableAddress()
method. But, unfortunately, this method is in NativeLibrary
class, not in the Library
interface!
And there also seems to be no way to get a NativeLibrary
instance when working with a custom interface (that is derived from the Library
interface) and with the Native.load()
method. I probably could use NativeLibrary.getInstance()
instead, in order to get a NativeLibrary
instance and to be able to use getGlobalVariableAddress()
. But then, how do I apply my Library
-interface to a NativeLibrary
instance in order to be able to invoke the functions?
Loading the same library twice, once via Native.Load()
in order to be able to call the functions via my interface, and once via NativeLibrary.getInstance()
in order to be able to get the global variable address, seems like a very ugly workaround/hack, provided that it would work at all.
So, to make a long story short, is there any way in JNA to go from the Library
interface to the underlying NativeLibrary
instance, or vice versa?
Or, alternatively, how to declare a global variable directly in the JNA interface? 🤔
Upvotes: 2
Views: 135
Reputation: 31
Based on the suggestion by Daniel Widdis, I was able to come up with a solution that is based on java.lang.reflect.Proxy
in order to get the Handler
instance out of the Library
interface via the Proxy.getInvocationHandler()
method, which then allows me to call getNativeLibrary()
on the Handler object to obtain the required NativeLibrary
instance:
import java.lang.reflect.Proxy;
import com.sun.jna.Library;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
public interface MyLibrary extends Library {
static final MyLibrary INSTANCE = Native.load("mylib123", MyLibrary.class);
static class NativeLibraryHolder {
public static final NativeLibrary NATIVE_LIBRARY = ((Handler)Proxy.getInvocationHandler(MyLibrary.INSTANCE)).getNativeLibrary();
}
static class SOME_GLOBAL_VARIABLE {
private static final Pointer ADDRESS = NativeLibraryHolder.NATIVE_LIBRARY.getGlobalVariableAddress("SOME_GLOBAL_VARIABLE");
int get() { return ADDRESS.getInt(0L); }
void set(final int newValue) { ADDRESS.setInt(0L, newValue); }
}
int some_function(int param);
}
Upvotes: 1
Reputation: 9131
As you've noted in your question, the NativeLibrary
class does provide a getGlobalVariableAddress()
method to which you can pass the native name of the variable as a string to retrieve a Pointer
to it. (Knowing the number of bytes to read from that pointer is something you have to determine manually.)
You can directly assign the NativeLibrary
to an instance and fetch the field like this:
NativeLibrary fooLib = NativeLibrary.getInstance("foo");
Pointer p = fooLib.getGlobalVariableAddress("SOME_GLOBAL_VARIABLE");
short s = p.getShort(0); // signed, convert to uint16
As for directly linking a Library
instance to the NativeLibrary
, it's not supported in the API. The Library
class itself is an interface, so doesn't define any methods pointing to the native library. It does have an inner class Handler
with a getNativeLibrary
method on it which is used as part of the load()
method in setting up the JDK Proxy
class. It looks like you could probably use methods on either Proxy
or InvocationHandler
to try to recover the class via reflection, but that's left as an exercise for the reader.
Upvotes: 0