java

Replacement for the deprecated URL(URL context, String spec) constructor that also works with older Java versions


I thought that the equivalent of new URL(URL context, String spec) that is deprecated in Java 21 would be context.toURI().resolve(String spec).toURL(). But it only gives the same results in Java 21. If I use an older Java version, like 17 or 11, I get different results. For example this code

    URL context = new URI("http://example.com").toURL();
    for (String spec : Arrays.asList("foo", "/foo", "http://foo.bar", "\\foo")) {
        System.out.println(new URL(context, spec));
        System.out.println(context.toURI().resolve(spec));
    }

produces this output in older Java versions

http://example.com/foo
http://example.comfoo
http://example.com/foo
http://example.com/foo
http://foo.bar
http://foo.bar
http://example.com/\foo
Exception in thread "main" java.lang.IllegalArgumentException: Illegal character in path at index 0: \foo
    at java.base/java.net.URI.create(URI.java:906)
    at java.base/java.net.URI.resolve(URI.java:1089)
    at Main.main(Main.java:10)
Caused by: java.net.URISyntaxException: Illegal character in path at index 0: \foo
    at java.base/java.net.URI$Parser.fail(URI.java:2974)
    at java.base/java.net.URI$Parser.checkChars(URI.java:3145)
    at java.base/java.net.URI$Parser.parseHierarchical(URI.java:3227)
    at java.base/java.net.URI$Parser.parse(URI.java:3186)
    at java.base/java.net.URI.<init>(URI.java:623)
    at java.base/java.net.URI.create(URI.java:904)
    ... 2 more

The last exception is thrown even in Java 21. I know that it's not a valid URL, but I don't control the input and browsers still work with it, so I have to make it work too.


Solution

  • This is due to a bug (JDK-8272702) in the Java library. This has been fixed in Java 17.0.7 and later versions.

    The bug will manifest itself depending on the version of JRE you run with, not the version you compile with. Therefore, even if you compile your project with a legacy version such as Java 8, the URI.resolve method will work correctly if you run it with 17.0.7 or later (such as 21 or 23).

    If you are worried that your users might run an old version of Java, your choices include: