public static void main(String[] args) {
    File root = new File("z:/a/b/c/d");
    File t1 = new File("z:/a/b/e/f");
    File t2 = new File("c:/t/r");
    File t3 = new File("z:/a/b/c/d/i/m");
    File t4 = new File("z:/a/b/c/d");

    System.out.println("Rel root, t1: " + makePathRelativeIfPossible(root, t1));
    System.out.println("Rel root, t2: " + makePathRelativeIfPossible(root, t2));
    System.out.println("Rel root, t3: " + makePathRelativeIfPossible(root, t3));
    System.out.println("Rel root, t4: " + makePathRelativeIfPossible(root, t4));

    File f1 = new File("f:\\a\\b");
    File f2 = new File("f:\\a\\c");
    File f3 = new File(f1, f2.toString());
    System.out.println("f3 = " + f3.toString());
  }
  // root : z:/a/b/c/d
  // t1:    z:/a/b/e/f
  // t2:    c:/t/r
  // t3:    z:/a/b/c/d/i/m
  // t4:    z:/a/b/c/d
  public static File makePathRelativeIfPossible(File root, File f) {
    if (f.toString().indexOf("${") >= 0) return f;

    File orgfile = f;
    try {
      if (f.isAbsolute() == false) {
        f = new File(root, f.toString());
      }
      f = f.getCanonicalFile();
      f = f.getAbsoluteFile();
      root = root.getCanonicalFile();
      root = root.getAbsoluteFile();
    } catch (IOException iox) {
      iox.printStackTrace();
      System.out.println("Failed, returning " + orgfile);

      return orgfile;
    }
    Vector rootvec = new Vector();
    Vector targetvec = new Vector();
    File cur;
    cur = root;
    while (cur != null) {
      String n = cur.getName();
      // lame hack, because getName() returns "" when the file is a drive (like c: or z:)
      if (n.equals("")) n = cur.getAbsolutePath();
      rootvec.add(0, n);
      cur = cur.getParentFile();
    }

    cur = f;
    while (cur != null) {
      String n = cur.getName();
      if (n.equals("")) n = cur.getAbsolutePath();
      targetvec.add(0, n);
      cur = cur.getParentFile();
    }

    // find the lowest common path
    int cursor = 0;
    while ((cursor < rootvec.size()) && (cursor < targetvec.size())) {
      if (rootvec.elementAt(cursor).equals(targetvec.elementAt(cursor)) == false) break;
      cursor++;
    }

    if (cursor == 0) return f;

    if ((cursor == rootvec.size()) && (cursor == targetvec.size())) return new File(".");

    StringBuffer buffer = new StringBuffer();
    for (int i = cursor; i < rootvec.size(); i++) {
      buffer.append("../");
    }

    for (int i = cursor; i < targetvec.size(); i++) {
      buffer.append(targetvec.elementAt(i).toString());
      buffer.append("/");
    }

    return new File(buffer.toString());
  }