0

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

billdoor
  • 1,999
  • 4
  • 28
  • 54
  • 2
    "ExtClass" != "TestClass". – Michael Mar 20 '18 at 15:32
  • That solves jni, thank you! - but how would that work with the JNA interface - which i would prefer? – billdoor Mar 21 '18 at 15:26
  • I've never used JNA, so I don't know. – Michael Mar 21 '18 at 15:35
  • 1
    JNI and JNA are not interchangeable. JNA is for "plain" functions. Functions created for JNI can't be called by JNA, because JNA does not create the two additional arguments `env` and `object`. – user2543253 Mar 22 '18 at 12:18
  • so JNA can only call functions that are not made for JNI explicitly? – billdoor Mar 22 '18 at 13:57
  • Yes. JNA and JNI sound similar but are conceptually different. JNI calls functions specifically made for it. JNA calls arbitrary functions in existing native libraries. To access an existing library (made for C programmers) from Java you can either create a wrapper library with JNI and its special functions or use JNA and access the functions directly (JNA uses libffi, wrapped with JNI, for that internally). – user2543253 Mar 22 '18 at 17:04
  • ok cool! could you please answer, so I can accept it? – billdoor Mar 22 '18 at 21:35

1 Answers1

1

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.

Community
  • 1
  • 1
user2543253
  • 2,143
  • 19
  • 20