JDK-5082706 : File constructor and methods don't consistently resolve relative paths against user.dir
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2004-08-04
  • Updated: 2006-12-14
  • Resolved: 2006-12-14
Related Reports
Duplicate :  
Description
Name: gm110360			Date: 08/04/2004


FULL PRODUCT VERSION :
java version "1.5.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta2-b51)
Java HotSpot(TM) Client VM (build 1.5.0-beta2-b51, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Windows 2000 Service Pack 4 (probably fails on all Operating Systems)

A DESCRIPTION OF THE PROBLEM :
The java.io.File class has behaviour which is contrary to the documentation. Relative paths are sometimes resolved against the directory named by  System.getProperty("user.dir"), which is the expected behaviour from the JavaDoc for this class. Sometimes however, relative names are resolved against the directory in the Java Virtual Machine was originally invoked (this behaviour is of no use to anyone!!!! eg. if you are developing in NetBeans [which starts the JVM] you cannot use relative paths with java.io.File as it sometimes ignores the directory you set as "user.dir").

The java.io.File documentation states (emphasis added by me):
       "By default the classes in the java.io package ALWAYS resolve relative
        pathnames against the current user directory. This directory is named
        by the system property user.dir, and is TYPICALLY the directory in
        which the Java virtual machine was invoked."

Yes, the JavaDoc also indicates that relative to absolute path resolution is also system dependent - which invalidates bot user expectation and the quote above.

This was originally reported as related bugs 4117557 as 4483097 and was *incorrectly* closed by the responsible engineer. All the client/user comments (below the main text of  the 4483097 bug report state this). The engineer's comments were:
  " Not a bug.  If you need to resolve a filename against the value of
the "user.dir" system property then you must use getAbsolutePath (or
getAbsoluteFile, or getCanonicalPath, or getCanonicalFile).  Simpler
operations such as exists() always resolve against the directory in
which the Java virtual machine was originally invoked (and no, there
is no way to change that).

--  xxxxx@xxxxx  2001/7/23"

However, this clearly contravenes both the JavaDoc for java.io.File, but also (and this is far worse) results in behaviour which users cannot control.

  Suggested fixes:

a) Fix the java.io.File class so that *ALL* relative names are resolved against the value of "user.dir". This is the behaviour that all user comments have requested (it was the behaviour they expected). The users that have looked at the Java source code believe it is possible to do from the publically available source code they have seen. It would fufil the user expected behaviour  and the specified semantics given in the java.io.File JavaDoc documentation. Yes I know that this solution takes time the maintainers have too little of, but  this is also the "right solution".
 
b) Change the java.io.File JavaDoc to indicate which methods ignore the user-specified "user.dir". This is a quick and easy fix for the maintainers, but pretty much renders relative paths unusable in java.io.File as the user has no way to consistently control the base path that relative files are resolved against.

In conclusion
-------------------
I think Java is great, but this bug should have been fixed years ago (saying it isn't a bug defies reality, all your users and the documentation unamimously think it is). No wonder so many people have become disillusioned with Java and are turning the the (vile) C#.NET - at least in C# the users control over relative directory resolution.



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See the example code below.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The printout from the example code should be:

relativeFileExists = true, absoluteFileExists = true

ie. relative file paths should always be resolved against the System property "user.dir".
ACTUAL -
The printout from the example code is:

relativeFileExists = false, absoluteFileExists = true

ie. relative file paths are only sometimes resolved against the System property "user.dir" and are sometimes resolved against a path in an undocumented manner.



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * TestFile.java
 *
 * Created on 29 July 2004, 14:47
*
*   NOTE: since relative paths don't work consistently in java.io.File
*                 you will have to set the variable workingDirectory (within the
*                 main() method of this class) to name the location where you
*                 placed this java file.
*
 */

import java.io.File;

public class TestFile
{
  public static void main(String args[])
  {
     String filename = "TestFile.java";

     // Change this path to name the absolute directory path where
     // this Java file is located.
     String workingDirectory = "H:\\source\\bi\\installer";
     
      // Run the test.
     TestFile test = new TestFile(filename, workingDirectory);
  }
    
    /** Creates a new instance of TestFile */
    public TestFile (String filename, String workingDirectory)
    {
      // Set the system property "user.dir" to a known state.
      System.setProperty("user.dir", workingDirectory);
      
      File relativeFile = new File(filename);
      File absoluteFile = new File(relativeFile.getAbsolutePath());
      
      // The following code returns false, as the relative path ignores the
      // "user.dir" property and resolves the file against the initial directory
      // that the JVM was invoked in. This contravenes the JavaDoc for
      // java.io.File which states:
      // "By default the classes in the java.io package always resolve relative
      //  pathnames against the current user directory. This directory is named
      //  by the system property user.dir, and is typically the directory in
      //  which the Java virtual machine was invoked."
      //
      boolean relativeFileExists = relativeFile.exists(); // ERROR: is false!
      
      // This returns true, as expected.
      boolean absoluteFileExists = absoluteFile.exists(); // is true.
      
      System.out.println("relativeFileExists = " + relativeFileExists + ", absoluteFileExists = " + absoluteFileExists);
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
  From bug 4483097:

  An ugly work-around is using getAbsoluteFile() on all File objects that came
  from "unknown" sources, and may therefore contain a relative path (e.g. user-
  supplied strings, as opposed to JFileChooser.)

However, this workaround is simply saying that relative paths can't be used in Java (which is pretty bad!!!!).
(Incident Review ID: 290252) 
======================================================================

Comments
EVALUATION The user.dir property is set at VM startup and should not be changed thereafter. There are assumptions in the implementation that the directory doesn't change. See 4117557 for further discussion on this issue.
13-10-2005

EVALUATION Not for Tiger. -- iag@sfbay 2004-08-05
05-08-2004