Search code examples
javajava-native-interface

java loadlibrary and native method declaration


In short: Obviously a native method must be declared in the same class as the loadLibrary call is issued. If the native method is declared in a static inner class, the binding fails.

Working example:

public class TestNative
{
    public TestNative()
    {
        System.loadLibrary( "mylibrary");
    }

    private native int nativeMethod();

    public void doit()
    {
        new NativeWrap().callNative();
    }

    class NativeWrap
    {
        int callNative()
        {
           return nativeMethod();    // <<<< works
        }
    }
}

Failing example:

public class TestNative2
{
    public TestNative2()
    {
        System.loadLibrary( "mylibrary");
    }

    public void doit()
    {
        new NativeWrap().callNative();
    }

    static class NativeWrap
    {
        int callNative()
        {
           return nativeMethod();   // <<<< throws UnsatisfiedLinkError 
        }

        private native int nativeMethod();
    }
}

BTW: The loadLibrary works in both examples.

I did not find any hints about this topic. All JNI examples I have found load the library in the same class as the native method is declared. Can someone shine some light on this stuff?


Solution

  • It works perfectly fine. Place, where you load library, doesn't matter. What matters here is name of the method. If you generate your method signature, and then move your method somewhere else, it will fail to run.

    Take a look here:

    package recipeNo001;
    
    public class HelloWorld {
    
      static {
        System.loadLibrary("HelloWorld");
      }
    
      private native void displayMessage();
    
      static class NativeWrapper {
        void callNative() {
          displayMessageInner();
        }
        private native void displayMessageInner();
      }
    
      public static void main(String[] args) {
        new HelloWorld().displayMessage();
        new NativeWrapper().callNative();
      }
    }
    

    But you have to make sure that you provide proper name inside library. Note the difference between two:

    JNIEXPORT void JNICALL Java_recipeNo001_HelloWorld_displayMessage
      (JNIEnv *env, jclass obj)
    JNIEXPORT void JNICALL Java_recipeNo001_HelloWorld_00024NativeWrapper_displayMessageInner
      (JNIEnv *env, jobject obj)
    

    And it works, of course.

    Hello world from enclosing class!
    Hello world from wrapper!
    

    And, in your case, you have yet another issue. If you don't load library in static block, you have to make sure to instantiate at least one object of the class before you call native method.

    Take a look here when it comes to sample code:

    https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo034