2

特定の Java API は、呼び出し元に依存します。1 つの (非常に文書化されていない IMO) 例はSystem.load()、一部の JNI コードを呼び出し元ClassLoaderのみにロードする です。

おおよそのようなラッパーがありますJniUtils.loadLibrary("nameoflibrary")。現在のアーキテクチャに適したライブラリを見つけて、JAR から抽出し、に渡しSystem.load()ます。しかし、の呼び出し元がそれ自体JniUtils.loadLibraryと同じでないClassLoader場合に遭遇しました。Jniこれにより、ライブラリが間違った にロードされ、ネイティブ メソッドが呼び出されるようClassLoaderになりました。UnsatisfiedLinkError

のような JVM 内部に依存せずにsun.reflect.Reflection.getCallerClass()、この問題を回避する方法はありますか? 私の現在の考えは、ラッパーを次のように変更することです。

public class JniUtils {
    public static void loadLibrary(String libraryName, MethodHandles.Lookup lookup);
}

これは次のように呼び出すことができます:

public class NeedsJni {
    static {
        JniUtils.loadLibrary("nameoflibrary", MethodHandles.lookup());
    }
}

を使用してメソッドLookupを解決して呼び出すと、 caller として保存する必要があります。System.load()NeedsJni

より良い回避策はありますか?

4

2 に答える 2

0

クラスパスに互換性がない場合に提供する必要がある抽象クラスを定義することを検討してください。これにより、呼び出し元が実装を提供する必要があるため、「呼び出し元の感度」が提供され、必要なコンテキストが提供されます。

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);
    }
}
于 2015-07-15T11:58:33.400 に答える