Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4679530

"file:" URLs: URI.toURL spec violated, host value inconsistency, equality issues

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Won't Fix
    • Icon: P4 P4
    • None
    • 1.4.0
    • core-libs
    • None
    • sparc
    • solaris_8

      The spec for for the method java.net.URI.toURL asserts:

      This convenience method works as if invoking it were equivalent to
      evaluating the expression

      new URL(this.toString())

      after first checking that this URI is absolute.

      But that equivalence assertion is currently violated for "file:" URLs,
      in 1.4.0 and Hopper today. The two approaches produce URL instances
      that are not equal to each other-- the difference is whether the URL's
      host value is null or empty string.

      More generally:

      Currently in 1.4.0 and Hopper, the following means of creating "file:"
      URLs create a URL with a host value of empty string:

      a) new URL("file:/tmp/")
      b) (new File("/tmp")).toURL()

      but these other means create a URL with a host value of null:

      c) new URI("file:/tmp/").toURL()
      d) (new File("/tmp")).toURI().toURL()

      Thus, a URL created by (a) or (b) will not be equal (by URL.equals) to
      a URL created by (c) of (d).

      It would seem highly desirable for URL instances created by all of (a),
      (b), (c), and (d)-- which all have the same external string forms-- to
      be considered equal by URL.equals.

      Put slightly differently, it would seem highly desirable to make the
      expression "u.equals(new URL(u.toExternalForm())" return true for as
      many kinds of URL instances "u" as reasonably possible.

      The behaviors of (c) and (d) do seem justified, because these URIs
      really do not have host components, and null is the value for not
      having a given component-- see 4496251, which is marked fixed and
      integrated in merlin-beta3, but was actually backed out because of
      4506291 (also for merlin-beta3).

      The seemingly reasonable equivalence assertion in the spec for
      URI.toURL, which claims that (c) should produce the same result as (a),
      is currently violated-- given that (c) seems to be doing the right
      thing, this would seem to indicate that (a) should be fixed (again--
      see Comments section), but then to keep 4506291 fixed as well, (b)
      would then have to be fixed also, so that all of these expressions would
      produce equivalent URL instances, with null host values.

      But would such a change in the behaviors or (a) or (b) raise any other
      compatibility issues?

      Below is a test program that demonstrates the above issues and example output of the program with 1.4.0 and the latest Hopper promoted build.

      import java.io.File;
      import java.net.URI;
      import java.net.URL;

      public class FileURL {

          public static void main(String[] args) throws Exception {
      String pathString = args[0];
      String pathURL = (new File(pathString)).toURL().toExternalForm();

      println();
      println("URL a = new URL(\"" + pathURL + "\")");
      println();

      URL a = new URL(pathURL);
      dumpURL(a);

      println();
      println("URL b = (new File(\"" + pathString + "\")).toURL()");
      println();

      URL b = (new File(pathString)).toURL();
      dumpURL(b);

      println();
      println("URL c = new URI(\"" + pathURL + "\").toURL()");
      println();

      URL c = new URI(pathURL).toURL();
      dumpURL(c);

      println();
      println("URL d = (new File(\"" + pathString + "\")).toURI().toURL()");
      println();

      URL d = (new File(pathString)).toURI().toURL();
      dumpURL(d);

      println();
      println("a.equals(b) returns " + a.equals(b));
      println("a.equals(c) returns " + a.equals(c));
      println("a.equals(d) returns " + a.equals(d));
      println("b.equals(a) returns " + b.equals(a));
      println("b.equals(c) returns " + b.equals(c));
      println("b.equals(d) returns " + b.equals(d));
      println("c.equals(a) returns " + c.equals(a));
      println("c.equals(b) returns " + c.equals(b));
      println("c.equals(d) returns " + c.equals(d));
      println("d.equals(a) returns " + d.equals(a));
      println("d.equals(b) returns " + d.equals(b));
      println("d.equals(c) returns " + d.equals(c));
          }

          private static void dumpURL(URL u) {
      println("external form: " + u.toExternalForm());
      println("\tprotocol: " + u.getProtocol());
      println("\tauthority: " + u.getAuthority());
      println("\tuser info: " + u.getUserInfo());
      println("\thost: " + u.getHost());
      println("\tport: " + u.getPort());
      println("\tpath: " + u.getPath());
      println("\tfile: " + u.getFile());
      println("\tquery: " + u.getQuery());
      println("\tref: " + u.getRef());
          }

          private static void println() { System.err.println(); }
          private static void println(String s) { System.err.println(s); }
      }

      [terrier] 71 % java -version
      java version "1.4.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
      Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)
      [terrier] 72 % java FileURL /tmp

      URL a = new URL("file:/tmp/")

      external form: file:/tmp/
      protocol: file
      authority: null
      user info: null
      host:
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      URL b = (new File("/tmp")).toURL()

      external form: file:/tmp/
      protocol: file
      authority:
      user info: null
      host:
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      URL c = new URI("file:/tmp/").toURL()

      external form: file:/tmp/
      protocol: file
      authority: null
      user info: null
      host: null
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      URL d = (new File("/tmp")).toURI().toURL()

      external form: file:/tmp/
      protocol: file
      authority: null
      user info: null
      host: null
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      a.equals(b) returns true
      a.equals(c) returns false
      a.equals(d) returns false
      b.equals(a) returns true
      b.equals(c) returns false
      b.equals(d) returns false
      c.equals(a) returns false
      c.equals(b) returns false
      c.equals(d) returns true
      d.equals(a) returns false
      d.equals(b) returns false
      d.equals(c) returns true

      [terrier] 74 % java -version
      java version "1.4.1-beta"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-beta-b10)
      Java HotSpot(TM) Client VM (build 1.4.1-beta-b10, mixed mode)
      [terrier] 75 % java FileURL /tmp

      URL a = new URL("file:/tmp/")

      external form: file:/tmp/
      protocol: file
      authority: null
      user info: null
      host:
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      URL b = (new File("/tmp")).toURL()

      external form: file:/tmp/
      protocol: file
      authority:
      user info: null
      host:
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      URL c = new URI("file:/tmp/").toURL()

      external form: file:/tmp/
      protocol: file
      authority: null
      user info: null
      host: null
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      URL d = (new File("/tmp")).toURI().toURL()

      external form: file:/tmp/
      protocol: file
      authority: null
      user info: null
      host: null
      port: -1
      path: /tmp/
      file: /tmp/
      query: null
      ref: null

      a.equals(b) returns true
      a.equals(c) returns false
      a.equals(d) returns false
      b.equals(a) returns true
      b.equals(c) returns false
      b.equals(d) returns false
      c.equals(a) returns false
      c.equals(b) returns false
      c.equals(d) returns true
      d.equals(a) returns false
      d.equals(b) returns false
      d.equals(c) returns true

            michaelm Michael McMahon
            peterjones Peter Jones (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: