Can't obtain static method的Error

有天某個客戶說我們的軟體服務無法啟動,傳回來的debug log中,包含以下錯誤:

java.lang.UnsatisfiedLinkError: Can't obtain static method fromNative(Method, Object) from class com.sun.jna.Native 

首先這個問題是由於JNA版本不同造成的。我們使用4.1.0版本的JNA,com.sun.jna.Native中並沒有fromNative(Method, Object),確認過JNA GitHub後,這應是4.3.0後加入的method。
因此,面對此問題,我懷疑可能是:

  • 我們軟體的third-party libraries包含新版本JNA。
  • 我們軟體參考到客戶電腦中的JNA。

第一個問題我透過Classpath Inspector確認過,並非我們問題。第二個問題,首先我透過設定CLASSPATH到環境變數中,並指定到4.3.0的jar檔路徑;可惜無法重現出問題(可能和service wrapper有關,無深究)。最後看了幾篇關於JNA與此相關的issue,推測應是JNA dll或so所造成的問題,所以我從jna.jar中抽取了jnidispatch.dll,並放置於PATH所設定的目錄中,就可以重現出此問題。


解決方式是在java啟動參數加入:

-Djna.nosys=true
從4.1.0版本的程式碼可以得知,當宣告此變數為true時,它會使用System.loadLibrary去讀jnidispatch,反之則是從classpath中讀:
if (!Boolean.getBoolean("jna.nosys")) {
            try {
		if (DEBUG_JNA_LOAD) {
		    System.out.println("Trying (via loadLibrary) " + libName);
		}
                System.loadLibrary(libName);
                if (DEBUG_JNA_LOAD) {
                    System.out.println("Found jnidispatch on system path");
                }
                return;
            }
            catch(UnsatisfiedLinkError e) {
            }
        }
        if (!Boolean.getBoolean("jna.noclasspath")) {
            loadNativeDispatchLibraryFromClasspath();
        }
        else {
            throw new UnsatisfiedLinkError("Unable to locate JNA native support library");
        }
假如客戶所裝軟體有使用到jnidispatch.dll且安裝於PATH中,就會有此問題。