Search code examples
apicompatibilityjava

Using Attach API Outside Of JDK


I have a small application that uses the Attach API to modify some third party classes during runtime. Alas, I have run into a large problem: the Attach API only comes with the JDK. The necessary files I can copy from the JDK and add into my project, but the library responsible for this(attach.(dll|so)) I can't. This is because I would have to copy attach.lib from a resource inside jar, and put it in the JRE/lib directory.

An action that would not work if the user isn't root on a Linux machine, therefore losing compatibility to alot of users (as this app is supposed to run on a server, and most servers are Linux, and I can't be sure all are root)

I looked into all the classes responsible for the attach API (VirtualMachine, AttachProvider etc) but found no place where it is loading the library.

Is it possible to do this? I mean, can I use the Attach API outside of a JDK installation? If so, how?


Solution

  • You can do so by modifying java.library.path:

    static void addToLibPath(String path) throws NoSuchFieldException,
                                                 SecurityException,
                                                 IllegalArgumentException,
                                                 IllegalAccessException
    {
        if (System.getProperty("java.library.path") != null) {
            // If java.library.path is not empty, we will prepend our path
            // Note that path.separator is ; on Windows and : on Unix-like,
            // so we can't hard code it.
            System.setProperty("java.library.path",
                               path + System.getProperty("path.separator")
                               + System.getProperty("java.library.path"));
        } else {
            System.setProperty("java.library.path", path);
        }
    
        // Important: java.library.path is cached
        // We will be using reflection to clear the cache
        Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible(true);
        fieldSysPath.set(null, null);
    }
    

    Call addToLibPath("path") will add "path" to java.library.path.

    Please note that java.library.path is cached, and reflection is required to clear the cache.