JNA direct call not working with argument Structure[] - java

I have a C++ function:
struct Result {
//...
};
bool doSomething(Result[]);
If I use the following JNA binding, the function call works fine:
public class Result extends Structure {
//...
}
public interface CPPLibrary extends Library {
public static final CPPLibrary INSTANCE = (CPPLibrary)Native.loadLibrary("dllname");
boolean doSomething(Result[]);
}
But with direct call, I hit an IllegalArgumentException saying class [Lcom.usta.Result; is not a supported argument type (in method calcPV01 in class com.usta.CPPLibrary). My JNA code for the direct call-mapping:
public class CPPLibrary implements Library {
Native.register("dllname");
public static native boolean doSomething(Result[]);
}
I can see in com.sun.jna.Function#convertArgument() explicitly handles Structure[] but com.sun.jna.Native#getConversion(), which is used by direct call-mapping, does not handle Structure[].

The conversion is trivial, just call Structure.getPointer() on the first element of your structure array (assuming that you got the array from Structure.toArray in the first place).
You're actually better off with that when using direct mapping; when passing non-primitive, non-pointer types the JNI layer has to call back into the VM to derive the appropriate native data.
Feel free to file an issue for support of Structure[] arguments in direct mappings. That should be supported (JNA documentation notes that arrays of Pointer/String/WString/NativeMapped are not supported).

If I use a different method signature:
boolean doSomething(Pointer results);
it does work. But then I have to convert from Result[] to a Pointer my self.

Related

Java JNA Linkedlist declaration

I need to access native C++ code .dll from Java application. native int function works well, but for Linkedlist Struct I cannot find any reference on the Internet how to declare the java interface
this C++ code
struct usb_relay_device_info
{
unsigned char *serial_number;
char *device_path;
usb_relay_device_type type;
usb_relay_device_info* next;
};
int EXPORT_API usb_relay_init(void);
struct usb_relay_device_info EXPORT_API * usb_relay_device_enumerate(void);
int EXPORT_API usb_relay_device_open(struct usb_relay_device_info* device_info);
This is the java part
public interface JNI extends Library {
JNI INSTANCE = (JNI) Native.loadLibrary("usb", JNI.class);
public static class usb_relay_device_info extends Structure {
public static class DeviceInfo extends usb_relay_device_info implements Structure.ByValue {
}
public byte[] serial_number = new byte[1024];
public String device_path;
public int type;
}
int usb_relay_init();
usb_relay_device_info.DeviceInfo usb_relay_device_enumerate();
int usb_relay_device_open(usb_relay_device_info.DeviceInfo deviceInfo);
}
I already created just the struct at the java code (NOT the Linkedlist Struct). So when I call the function the values are not showing up because it supposed to be a list (linkedlist in C++)
You say "I cannot find any reference on the Internet how to declare the java interface" but there are plenty of references, including JNA's Overview, linked to the main project page.
There you will find that char * is a C String and should be mapped to Java's String.
The usb_relay_device_type mapping has to be referenced in the API that you're mapping. In this case it is an enum type, which is an integer, so int is probably appropriate here. (There are cases where it can be a smaller integer value like short or byte but those are rare.)
As for the pointer to the next device, that is also referenced on the overview page under struct*. The link (or explicitly) links to Structure.ByReference. That may not be obvious, but the JNA FAQ, also linked on the main JNA project page, amplifies. If it's still not clear, here's a summary:
By default, Structures listed as fields inside a Structure are treated "By Value", that is, the full structure and its fields are inserted in line. To get this behavior you can simply declare the structure name.
If you want the opposite behavior (By Reference) then you must explicitly state that, and JNA will map a pointer to the structure elsewhere. This is the case you have, and the correct structure mapping is usb_relay_device_info.ByReference. (You'll also need to change the structure declaration to implement ByReference -- the JNA overview, linked above, has an example of this.)
When used in function arguments, such as usb_relay_device_open(), the opposite is true: the "By Reference" is the default, and you only need to explicity specify "By Value" if that's relevant. In this case, it's not -- the native declaration includes the pointer: (usb_relay_device_info*) so you want the ByReference behavior. You can just put usb_relay_device_info device_info there and the ByReference will be implicit. Or, if you prefer (it's not needed) you could do usb_relay_device_info.ByReference device_info and it would just be redundant.
So in summary your structure mapping should be:
class usb_relay_device_info extends Structure {
public static class ByReference extends usb_relay_device_info implements Structure.ByReference { }
public String serial_number;
public String device_path;
public int type;
public usb_relay_device_info.ByReference next;
};
You'll need to add the FieldOrder, preferably using an annotation.

JNI / JNA Unsatisfied Link, but symbol is present

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

Loading a static void C function via AndroidfromJNI another Package

I am trying some things out with JNI and by that I found the following problem:
If I want to use a native function in Java I load the needed lib, in which the needed function is stored, via
static{
System.loadLibrary("lib");
}
and use
native private static int calculate(byte[] numberArray);
to declare the native method in the java file. During the program itself I can use this function to calculate something with:
int result = calculate(array);
This works only if I compiled the shared object with the header-file created by javah so that each function is named on c side as:
static void Java_com_packagename_File_calculate(const void* array, void* result){
code[...]
}
If I delete the reference in the java code ("native [...] calculate[...]")to this c function; is there any possibility to access / execute the still existing c-code via java (of course without editing the exisiting file ;-)) for example via reflections or inheritance? Or is there something possible like:
public class NewClass{
public int nativeCheater(){
System.loadLibrary("lib");
native private static int Java_com_packagename_File_calculate;
}
}
It is important that I want to use a whole new class without any relations to the prior used package com.packagename.(File).
Thanks in advance :-)
No, but you can create a new class with same package and class name and access the same native method. The new class can declare this method public.
An alternative is to use dynamic binding via Jni_OnLoad() and RegisterNatives(). This way, your native implementations may bind to any Java class, or even more than one.
But if you have access neither to the Java class nor to the native source, you can always create your own native method, in your own class, and inside your C explicitly call the original:
static void Java_com_mypackagename_File_calculate(const void* array, void* result) {
Java_com_packagename_File_calculate(array, result);
}

How can I conveniently wrap a caller-sensitive API?

Certain Java APIs are caller-sensitive. One (woefully underdocumented IMO) example is System.load(), which loads some JNI code into the caller's ClassLoader only.
I have a wrapper that looks roughly like JniUtils.loadLibrary("nameoflibrary"). It finds the appropriate library for the current architecture, extracts it out of the JAR, and passes it to System.load(). But I just ran into a case where the caller of JniUtils.loadLibrary wasn't in the same ClassLoader as Jni itself. That caused the library to get loaded into the wrong ClassLoader, resulting in UnsatisfiedLinkError once the native methods got called.
Without relying on JVM internals like sun.reflect.Reflection.getCallerClass(), is there a way to work around this issue? My current idea is to change the wrapper like this:
public class JniUtils {
public static void loadLibrary(String libraryName, MethodHandles.Lookup lookup);
}
which can be called like this:
public class NeedsJni {
static {
JniUtils.loadLibrary("nameoflibrary", MethodHandles.lookup());
}
}
Using the Lookup to resolve and call the System.load() method should preserve NeedsJni as the caller.
Is there a better workaround?
Depending on the complexity of your problem, this may or may not be applicable.
Under a context without reflection, it's hard for standard java code to replicate caller-sensitivity, even more so to "emulate" it to a caller-sensitive function. Even if it were done the code, in my opinion, would be incredibly obscure or would deal with deep dark language features that I would consider unnecessary.
The fundamental problem you have here is that System.load() is caller sensitive and you're trying to build your own "enhanced" System.load() by doing a bunch of other tasks prior to calling System.load() yourself. Why not leave System.load() exactly where it was when you started?
Rather than trying to replace the functionality of System.load(), complement it with your JniUtils class. Write a JniUtils.fetchLibrary() which returns a string in which the original caller can load from. Even better, return a custom object Library (or other names to that equivalent) containing a method that allows the retrieval of the string that should be passed to System.load(). From this, the call to load() can come from the point of need whilst your caller-insensitive code can do all the initialization separately.
Something to this example would be good:
public class JniUtils {
private static final HashMap<String, JniLibrary> cachedLibs = new HashMap<>();
public static JniLibrary fetchLibrary(String libname){
// Check cache for library
if(cachedLibs.containsKey(libname)){
return cachedLibs.get(libname);
}else{
JniLibrary lib = preloadLibrary(libname);
if(lib != null){
cachedLibs.put(libname, lib);
}
return lib;
}
}
/**
* Internal logic to prepare and generate a library instance
*
* #return JNI library on success, null on failure.
*/
private static JniLibrary preloadLibrary(String libname){
// Find lib
// Extract
// Get path
// Construct JniLibrary instance
// Return library as appropriate
}
/**
* Class representing a loadable JniLibrary
*/
public class JniLibrary{
public String getLibraryPath();
// Other potentially useful methods
}
}
public class NeedsJni {
static {
JniLibrary lib = JniUtils.fetchLibrary("nameoflibrary");
if(lib != null){
System.load(lib.getLibraryPath()); // Caller-sensitivity respected
}else{
// Well.... this is awkward.
}
}
}
not only does that solve the caller-sensitivity issue, the additional caching prevents additional extraction/architecture lookup and eventual failure (since the file you extract to would probably have been in use), allowing multiple calls to System.load() from different classes under different classloaders as appropriate.
The countercase to this approach is that if there is important code that has to be executed right after System.load() in your custom loadLibrary() method (suddenly, you wished java would have some sort of "OnLibraryLoad" event). In that case, perhaps add a method to run the post-load code within your main JniUtils class or the returned Library class (it's more ugly I know, but with clear documentation, it can't be that bad).
Consider defining an abstract class which has to be provided if the classpath is going to be incompatible. This provides "caller sensitivity" as the caller has to provide the implementation, thus providing the necessary context.
public class JniUtils {
public static void loadLibrary(String libraryName, Delegate delegate) {
//use delegate's provided classloader to find the native library from within the jar and extract
//ask the delegate to load the extracted library
}
public static abstract class Delegate {
/**
* #return The specific ClassLoader instance to use to find the native resource. If returning null, the ClassLoader of JniUtils will be used.
*/
public ClassLoader getLibraryClassLoader() {
return getClass().getClassLoader();
}
/**
* <p>
* The callback method which will be called once the native library's name has been
* resolved. This MUST be implemented by the subclass, so that it resolves as the "caller"
* class for {#link System#loadLibrary(String)}.
* </p>
*
* #param libraryName The name of the library to load.
*/
public abstract void loadLibrary(String libraryName);
}
}

How do I use a Java-defined instance method in Lua?

I'm aware that it is possible to use Java defined static methods in Lua, due to the section "Libraries of Java Functions" on http://luaj.org/luaj/README.html.
However I am struggling to find out how I can use the same for instance methods, I have a shortened example here:
private static class CallbackStore {
public void test(final String test) {
}
}
(I am aware that I can use a static method here as well, but it is not possible with the real life scenario)
I am using the following Lua code:
-- Always name this function "initCallbacks"
function initCallbacks(callbackStore)
callbackStore.test("test")
end
Which does not work as it is expecting userdata back, but I give it a string.
And I call the Lua code like this:
globals.load(new StringReader(codeTextArea.getText()), "interopTest").call();
CallbackStore callbackStore = new CallbackStore();
LuaValue initCallbacks = globals.get("initCallbacks");
initCallbacks.invoke(CoerceJavaToLua.coerce(callbackStore));
where the Lua code is returned by codeTextArea.getText()
Bottom line of my question is, how do I make my code running with test as an instance method?
When accessing member functions (in Lua objects in general, not just luaj) you have to provide the this argument manually as the first argument like so:
callbackStore.test(callbackStore,"test")
Or, you can use the shorthand notation for the same thing:
callbackStore:test("test")

Categories

Resources