java.io.File relative path's not working after calling a native method.

Hi guys,

I have a doozy of a problem using JNI from within my Java application.

I do a lot of file work (using java.io.File) which uses file path's relative to the installation directory (if running from c:\foo\bar I will be accessing a directory "baz", which is in absolute terms in c:\foo\bar\baz).

I have several unit tests (thank god, otherwise I wouldn't have ever noticed this problem) that have all run successfully for months now (creating new files, moving files, deleting files etc.), but since we've added some JNI calls to an external C library these tests fail.

I have tried running my test-suite (TestNG, it really beats JUnit!) without the tests for the JNI code and they pass successfully (so I know my code works correctly). I have also tried running the suite over and over in a loop, and then tried calling the native methods at different points in the loop, but any operation I perform with a file after calling the native method fail.

I have also tried using relative and absolute paths for my -Djava.library.path pointing to where my DLL's are located, but this has no impact on it. I have also tried printing out the "user.dir" System property before and after the native method call (to see if the native code was moving the working directory for some reason) and they are the same.

I can reproduce this problem reliably (unfortunately this is a proprietary system, so I can't really release code to the public) and it is all caused by the native call (I've stripped _everything_ else out to be only the file operations and the native code in a seperate test case).

I have a workaround, and that is to instantiate new File object's using the getAbsolutePath() of an already existing File object, however this does seem overkill (there is a _lot_ of file processing going on, so I'm sure to miss something). Has anybody else had this problem, and managed to find a workaround that doesn't resort to changing all of my existing relative path code to use absolute paths?

[2049 byte] By [Aidosa] at [2007-10-3 8:49:36]
# 1

At a guess I would say that something in your native code is changing the "current working directory".

My rule of thumb is to NEVER depend on files being relative to CWD; I would suggest that if you are always working relative to the load directory, then you construct your paths on the fly so that they are actually absolute paths.

bschauwejavaa at 2007-7-15 3:58:55 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 2

Thankyou for your reply.

I printed out System.getProperty("user.dir") before and after the native call and they have the exact same value (which according to the 1.5.0_06 javadoc is the user's current working directory). So I'm reasonably confident that it isn't changing the CWD on me in the native code (unless of course this property is one of those that is loaded into the VM at startup and then never adjusted again).

Is there another way for me to print out the CWD of my java app?

Aidosa at 2007-7-15 3:58:55 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 3
Oops double posted.null
Aidosa at 2007-7-15 3:58:55 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 4
1. I strongly suspect that user.dir never is changed.2. Why don't you write a simple native function to print the CWD? Call it before you use one of those native libraries. Then call it afterwards.
bschauwejavaa at 2007-7-15 3:58:55 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 5

Problem Solved!

After playing around with some code, I eventually placed some code before and after the call to the SDK for the library we were using, to display the working directory.

The initial question was correct, the working directory was being changed by the call to the external SDK, however the "user.dir" property retrieved by System.getProperty() does not change (I'm still assuming that these are set at startup of the VM, and never changed).

For anyone else that comes across this problem you can get the Current Working Directory (CWD) on windows by using the following function:

ulong GetCurrentDirectoryA(ulong BufferLen, ref string currentdir) LIBRARY "Kernel32.dll"

To set the CWD you can use the following function:

boolean SetCurrentDirectoryA(ref string cdir) LIBRARY "kernel32.dll"

To get around this problem (to avoid having to use absolute path's everywhere) we read the CWD out, call the SDK and then set the CWD back to what it was before the SDK invocation and all the relative path's work fine.

Thanks everyone for their suggestions/comments.

Aidosa at 2007-7-15 3:58:55 > top of Java-index,Java HotSpot Virtual Machine,Specifications...