Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding new paths for native libraries at runtime in Java

Is it possible to add a new path for native libraries at runtime ?. (Instead of starting Java with the property java.library.path), so a call to System.loadLibrary(nativeLibraryName) will include that path when trying to find nativeLibraryName. Is that possible or these paths are frozen once the JVM has started ?

like image 568
Sergio Avatar asked Mar 14 '13 12:03

Sergio


People also ask

How do I change the Java library PATH in eclipse?

Go to Project properties->Java Build Path->Source. You'll find a list of source-folders. Each entry under the the Source tab has Native library locations. It supports paths within the workspace and it will make Eclipse add it to your java.

What is native library PATH?

Native libraries are platform-specific library files, including . dll, . so, or *SRVPGM objects, that can be configured within shared libraries. Native libraries are visible to an application class loader whenever the shared library is associated with an application.

How do I change the Java library PATH in Windows 10?

(still within the Project Properties dialog) Click on the "Run/Debug Settings", select your Java class, then click on the "Edit..." button. Select the "Arguments" tab, then add -Djava. library. path="C:\chilkatJava;${env_var:PATH}" where "C:\chilkatJava" is the directory path containing the "chilkat.


2 Answers

[This solution don't work with Java 10+]

It seems impossible without little hacking (i.e. accessing private fields of the ClassLoader class)

This blog provide 2 ways of doing it.

For the record, here is the short version.

Option 1: fully replace java.library.path with the new value)

public static void setLibraryPath(String path) throws Exception {
    System.setProperty("java.library.path", path);

    //set sys_paths to null so that java.library.path will be reevalueted next time it is needed
    final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
    sysPathsField.setAccessible(true);
    sysPathsField.set(null, null);
}

Option 2: add a new path to the current java.library.path

/**
* Adds the specified path to the java library path
*
* @param pathToAdd the path to add
* @throws Exception
*/
public static void addLibraryPath(String pathToAdd) throws Exception{
    final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
    usrPathsField.setAccessible(true);

    //get array of paths
    final String[] paths = (String[])usrPathsField.get(null);

    //check if the path to add is already present
    for(String path : paths) {
        if(path.equals(pathToAdd)) {
            return;
        }
    }

    //add the new path
    final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
    newPaths[newPaths.length-1] = pathToAdd;
    usrPathsField.set(null, newPaths);
}
like image 123
ben75 Avatar answered Oct 16 '22 00:10

ben75


I used this in Java 12/13 which should work for any JVM with MethodHandles:

Lookup cl = MethodHandles.privateLookupIn(ClassLoader.class, MethodHandles.lookup());
VarHandle sys_paths = cl.findStaticVarHandle(ClassLoader.class, "sys_paths", String[].class);
sys_paths.set(null);

It has the benefit of being a Java API.

It is replaces the:

    final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
    sysPathsField.setAccessible(true);
    sysPathsField.set(null, null);
like image 25
Matthew Gerring Avatar answered Oct 16 '22 01:10

Matthew Gerring