mardi 14 juillet 2015

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?





Aucun commentaire:

Enregistrer un commentaire