Skip to content

Commit

Permalink
Merge pull request #1038 from matthiasblaesing/error_reporting_librar…
Browse files Browse the repository at this point in the history
…y_loading

Improve exception when native library loading fails
  • Loading branch information
matthiasblaesing authored Nov 24, 2018
2 parents 9449665 + 3bfd0cd commit e5b34ec
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Release 5.1.1 (Next release)

Features
--------
* [#1038](https://github.com/java-native-access/jna/issues/1038): Improve exception when native library loading fails by preserving the original exceptions and messages - [@matthiasblaesing](https://github.com/matthiasblaesing).

Bug Fixes
---------
Expand Down
78 changes: 71 additions & 7 deletions src/com/sun/jna/NativeLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.io.InputStreamReader;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -45,6 +46,8 @@
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Provides management of native library resources. One instance of this
Expand Down Expand Up @@ -148,6 +151,7 @@ private static NativeLibrary loadLibrary(String libraryName, Map<String, ?> opti
System.out.println("Looking for library '" + libraryName + "'");
}

List<Throwable> exceptions = new ArrayList<Throwable>();
boolean isAbsolutePath = new File(libraryName).isAbsolute();
List<String> searchPath = new ArrayList<String>();
int openFlags = openFlags(options);
Expand Down Expand Up @@ -192,8 +196,10 @@ private static NativeLibrary loadLibrary(String libraryName, Map<String, ?> opti
} catch(UnsatisfiedLinkError e) {
// Add the system paths back for all fallback searching
if (Native.DEBUG_LOAD) {
System.out.println("Loading failed with message: " + e.getMessage());
System.out.println("Adding system paths: " + librarySearchPath);
}
exceptions.add(e);
searchPath.addAll(librarySearchPath);
}

Expand All @@ -208,7 +214,11 @@ private static NativeLibrary loadLibrary(String libraryName, Map<String, ?> opti
throw new UnsatisfiedLinkError("Failed to load library '" + libraryName + "'");
}
}
} catch(UnsatisfiedLinkError e) {
} catch(UnsatisfiedLinkError ule) {
if (Native.DEBUG_LOAD) {
System.out.println("Loading failed with message: " + ule.getMessage());
}
exceptions.add(ule);
// For android, try to "preload" the library using
// System.loadLibrary(), which looks into the private /data/data
// path, not found in any properties
Expand All @@ -221,7 +231,10 @@ private static NativeLibrary loadLibrary(String libraryName, Map<String, ?> opti
handle = Native.open(libraryPath, openFlags);
}
catch(UnsatisfiedLinkError e2) {
e = e2;
if (Native.DEBUG_LOAD) {
System.out.println("Loading failed with message: " + e2.getMessage());
}
exceptions.add(e2);
}
}
else if (Platform.isLinux() || Platform.isFreeBSD()) {
Expand All @@ -240,7 +253,10 @@ else if (Platform.isLinux() || Platform.isFreeBSD()) {
handle = Native.open(libraryPath, openFlags);
}
catch(UnsatisfiedLinkError e2) {
e = e2;
if (Native.DEBUG_LOAD) {
System.out.println("Loading failed with message: " + e2.getMessage());
}
exceptions.add(e2);
}
}
}
Expand All @@ -258,7 +274,10 @@ else if (Platform.isMac() && !libraryName.endsWith(".dylib")) {
handle = Native.open(libraryPath, openFlags);
}
catch(UnsatisfiedLinkError e2) {
e = e2;
if (Native.DEBUG_LOAD) {
System.out.println("Loading failed with message: " + e2.getMessage());
}
exceptions.add(e2);
}
}
}
Expand All @@ -275,7 +294,10 @@ else if (Platform.isWindows() && !isAbsolutePath) {
try {
handle = Native.open(libraryPath, openFlags);
} catch(UnsatisfiedLinkError e2) {
e = e2;
if (Native.DEBUG_LOAD) {
System.out.println("Loading failed with message: " + e2.getMessage());
}
exceptions.add(e2);
}
}
}
Expand All @@ -295,12 +317,27 @@ else if (Platform.isWindows() && !isAbsolutePath) {
}
}
catch(IOException e2) {
e = new UnsatisfiedLinkError(e2.getMessage());
if (Native.DEBUG_LOAD) {
System.out.println("Loading failed with message: " + e2.getMessage());
}
exceptions.add(e2);
}
}

if (handle == 0) {
throw new UnsatisfiedLinkError("Unable to load library '" + libraryName + "': " + e.getMessage());
StringBuilder sb = new StringBuilder();
sb.append("Unable to load library '");
sb.append(libraryName);
sb.append("':");
for(Throwable t: exceptions) {
sb.append("\n");
sb.append(t.getMessage());
}
UnsatisfiedLinkError res = new UnsatisfiedLinkError(sb.toString());
for(Throwable t: exceptions) {
addSuppressedReflected(res, t);
}
throw res;
}
}

Expand All @@ -310,6 +347,33 @@ else if (Platform.isWindows() && !isAbsolutePath) {
return new NativeLibrary(libraryName, libraryPath, handle, options);
}

private static Method addSuppressedMethod = null;
static {
try {
addSuppressedMethod = Throwable.class.getMethod("addSuppressed", Throwable.class);
} catch (NoSuchMethodException ex) {
// This is the case for JDK < 7
} catch (SecurityException ex) {
Logger.getLogger(NativeLibrary.class.getName()).log(Level.SEVERE, "Failed to initialize 'addSuppressed' method", ex);
}
}

private static void addSuppressedReflected(Throwable target, Throwable suppressed) {
if(addSuppressedMethod == null) {
// Make this a NOOP on an unsupported JDK
return;
}
try {
addSuppressedMethod.invoke(target, suppressed);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to call addSuppressedMethod", ex);
} catch (IllegalArgumentException ex) {
throw new RuntimeException("Failed to call addSuppressedMethod", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to call addSuppressedMethod", ex);
}
}

/** Look for a matching framework (OSX) */
static String matchFramework(String libraryName) {
File framework = new File(libraryName);
Expand Down

0 comments on commit e5b34ec

Please sign in to comment.