Linking to native code in Java is always a hassle. JNI isn’t exactly nice, and there are some oddities around classloaders and native libraries which are annoying if you run into them.
One thing I wasn’t aware of was exactly how hard it is to load a library it isn’t already in the directories specified by the java.library.path system property.Â
Initially, I thought I’d just be able to alter that property and the JVM would pick up the new locations. That turns out not to be the case, as is shown by this (closed) bug report.
However, there is a solution, outlined in this post on the Sun forums, which revolves around altering the usr_paths field stored in java classes.
public static void addDir(String s) throws IOException { try { // This enables the java.library.path to be modified at runtime // From a Sun engineer at http://forums.sun.com/thread.jspa?threadID=707176 // Field field = ClassLoader.class.getDeclaredField("usr_paths"); field.setAccessible(true); String[] paths = (String[])field.get(null); for (int i = 0; i < paths.length; i++) { if (s.equals(paths[i])) { return; } } String[] tmp = new String[paths.length+1]; System.arraycopy(paths,0,tmp,0,paths.length); tmp[paths.length] = s; field.set(null,tmp); System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + s); } catch (IllegalAccessException e) { throw new IOException("Failed to get permissions to set library path"); } catch (NoSuchFieldException e) { throw new IOException("Failed to get field handle to set library path"); } }
Obviously, I don’t think that’s portable across JVMs, though.
I prefer loading native libs from a known place, e.g. a ‘lib’ subfolder or even better the directory of the jar, your class was loaded from.
See System.load(String).
Yes, that would normally be the sensible thing to do. However, in this case I was using a pre-packaged library (JNotify), which used System.loadLibrary(String), and so required the library to be on the library path.