Menu

#104 wrapper.working.dir does not affect NIO2 API

All
closed-works-for-me
nobody
None
5
2015-12-23
2015-01-02
No

Setting wrapper.working.dir does not affect the NIO2 filesystem API. This is a JVM-dependent issue. I am using Oracle 8u20, but this could also affect non-Oracle/OpenJDK JVMs.

Suppose YAJSW's working directory is "C:/foo". If you set wrapper.working.dir to "C:/bar", then try running a Java application that does something like

Path p = Paths.get("relative").toAbsolutePath();

p will point to C:/foo/relative, not C:/bar/relative

It looks like the problem stems from how the NIO2 API is implemented in OpenJDK/Oracle JVMs. The default filesystem is created when FileSystems is referenced by another class that needs to be loaded. The constructors for both sun.nio.fs.UnixFileSystem and WindowsFileSystem take a path parameter that is used as the "default directory". The value passed is the value of the "user.dir" system property. Because the default filesystem is cached for later use, any change to user.dir after the default filesystem is created will not affect the NIO2 APIs.

I managed to engineer a hack to "fix" this, by recreating the default filesystem after user.dir has been changed:

        try {
            Class<?> fsClass = Class.forName("java.nio.file.FileSystems$DefaultFileSystemHolder");
            Method defaultFsMethod = fsClass.getDeclaredMethod("defaultFileSystem");
            defaultFsMethod.setAccessible(true);

            Field defaultFsField = fsClass.getDeclaredField("defaultFileSystem");
            defaultFsField.setAccessible(true);
            FieldUtils.removeFinalModifier(defaultFsField);

            defaultFsField.set(null, defaultFsMethod.invoke(null));
        } catch (Exception e) {
            System.err.println("Failed to apply NIO2 Path hackfix");
            e.printStackTrace();
        }

FieldUtils is from Apache Commons-Lang 3. This solution is not perfect. Any Path created before the default filesystem is replaced will still refer to the wrong working directory because Path objects retain a reference to the FileSystem that created them, but this does at least fix any Path objects created after the replacement. Also, this presumably does not work on JVMs not derived from OpenJDK, such as the IBM JVM. But then again, the IBM JVM may not have this problem to begin with.

Discussion

  • rzo

    rzo - 2015-01-06

    hello,

    thanks for your feedback.

    i tried to reproduce the issue but could not.

    yajsw: 12.00, jdk: 1.7

    in the configuration i set wrapper.working.dir
    in the main method of the wrapped application i invoke:

    System.out.println(Paths.get(".").toAbsolutePath());

    i installed the application as windows service and run it.
    it logs the same path as the one set for wrapper.working.dir.

    The method WindowsXPProcess.changeWorkingDir(String) also sets the system property user.dir.

    Could you pls provide some more input how to reproduce the issue.

    -- Ron

     
  • Rich DiCroce

    Rich DiCroce - 2015-01-07

    I am using YAJSW 11.11, since 12.00 is still in alpha.

    Which JVM are you using? Oracle? This is a JVM-specific issue and I don't know if it occurs in Oracle/OpenJDK 1.7. I am currently using Oracle 8u20.

     
  • rzo

    rzo - 2015-12-23

    seems to work with release 12.04

     
  • rzo

    rzo - 2015-12-23
    • status: open --> closed-works-for-me
     

Log in to post a comment.