27

Given a string, how do I determine if it is an absolute URL or a relative URL in Java? I tried the following code:

private boolean isAbsoluteURL(String urlString) {
    boolean result = false;
    try
    {
        URL url = new URL(urlString);
        String protocol = url.getProtocol();
        if (protocol != null && protocol.trim().length() > 0)
            result = true;
    }
    catch (MalformedURLException e)
    {
        return false;
    }
    return result;
}

The problem is that all relative URLs (www.google.com or /questions/ask). are throwing a MalformedURLException because there is no protocol defined.

khalsa
  • 273
  • 1
  • 4
  • 5
  • 2
    ... so you catch the exception and return false, indicating that the relative URL is not, in fact, an absolute URL; which is the expected result. So how is that a problem? – Karl Knechtel Dec 08 '10 at 18:13
  • "www.google.com" and "/questions/ask" are not URLs. They may be absolute or relative URIs, depending on the implied URL scheme. So this code falls under the category of "works as expected." – cdhowie Dec 08 '10 at 18:14
  • Be aware URL uses your network connection – OscarRyz Dec 08 '10 at 18:15
  • 4
    `/` is an absolute URL for `file:` but it is relative for `http:`. If you don't know the base URL (acutally, the protocol), you cannot determine the relativeness of the given URL. In your example - `www.google.com` is a relative URL, so your method is correct and specification-compliant in this case, but it doesn't solve your problem. – khachik Dec 08 '10 at 18:22

4 Answers4

52

How about this:

final URI u = new URI("http://www.anigota.com/start");
// URI u = new URI("/works/with/me/too");
// URI u = new URI("/can/../do/./more/../sophis?ticated=stuff+too");

if (u.isAbsolute())
{
  System.out.println("Yes, I am absolute!");
}
else
{
  System.out.println("Ohh noes, it's a relative URI!");
}

More info here.

Chris
  • 15,429
  • 19
  • 72
  • 74
  • 6
    This doesn't appear to work with [Protocol Urls](http://www.paulirish.com/2010/the-protocol-relative-url/) (urls like //). You can [try it out at IDEOne](http://ideone.com/9AlUkU) – Brad Parks Jun 09 '15 at 19:06
  • which can be used to do absolute redirects, [like in this example](http://jsfiddle.net/3f0gqvbf/1/) – Brad Parks Jun 09 '15 at 19:29
  • note you still have to handle an exception : URISyntaxException. It doesn't seem to bother OP but in my case I would have preferred a true one-liner solution – user1075613 Jul 23 '18 at 18:29
  • 1
    @user1075613 `URI.create` – Abhijit Sarkar Jan 03 '19 at 22:56
  • @Abhijit Sarkar you should post this as an answer (else I will do :p) I would vote for you! – user1075613 Jan 07 '19 at 17:31
  • @user1075613 It doesn't stand as a separate answer, because the OP didn't ask how to create a `URI` without throwing checked exceptions. If you post an answer with only that change, it's likely to be downvoted, beginning with me. – Abhijit Sarkar Jan 07 '19 at 20:54
3

As I said in in my comment, you have to normalize the URL before checking it, and that normalization depends on your application, since www.google.com is not an absolute URL. Here is an example code, which can be used to check URLs to be absolute:

import java.net.URL;

public class Test {
  public static void main(String [] args) throws Exception {
    String [] urls = {"www.google.com",
                      "http://www.google.com",
                      "/search",
                      "file:/dir/file",
                      "file://localhost/dir/file",
                      "file:///dir/file"};
    
    for (String url : urls) {
      System.out.println("`" + url + "' is " + 
                          (isAbsoluteURL(url)?"absolute":"relative"));
    }
  }

  public static boolean isAbsoluteURL(String url)
                          throws java.net.MalformedURLException {
    final URL baseHTTP = new URL("http://example.com");
    final URL baseFILE = new URL("file:///");
    URL frelative = new URL(baseFILE, url);
    URL hrelative = new URL(baseHTTP, url);
    System.err.println("DEBUG: file URL: " + frelative.toString());
    System.err.println("DEBUG: http URL: " + hrelative.toString());
    return frelative.equals(hrelative);
  }
}

Output:

~$ java Test 2>/dev/null
`www.google.com' is relative
`http://www.google.com' is absolute
`/search' is relative
`file:/dir/file' is absolute
`file://localhost/dir/file' is absolute
`file:///dir/file' is absolute
khachik
  • 28,112
  • 9
  • 59
  • 94
2

This is a snippet I use to ensure links are absolute:

private String ensureAbsoluteURL(String base, String maybeRelative) {
    if (maybeRelative.startsWith("http")) {
        return maybeRelative;
    } else {
        try {
           return new URL(new URL(base), maybeRelative).toExternalForm();
        } catch (MalformedURLException e) {
           // do something
        }
    }
}
Renaud
  • 16,073
  • 6
  • 81
  • 79
1

I made this:

public static String processUrl(String urlToProcess, String grantedNormalUrl){
    if (urlToProcess.startsWith("//")){
        urlToProcess = checkUrlStartsWithProtocol(urlToProcess);
        return urlToProcess;
    }

    if (!isAbsolute(urlToProcess)){
        String rootPage = extractRootPage(grantedNormalUrl);
        boolean domainEndsWithSlash = rootPage.endsWith("/");
        boolean urlStartsWithSlash = urlToProcess.startsWith("/");
        if (domainEndsWithSlash && urlStartsWithSlash){
            rootPage = rootPage.substring(0, rootPage.length() - 1); // exclude /
        }
        urlToProcess = rootPage + (!(domainEndsWithSlash || urlStartsWithSlash) ? "/" : "") + urlToProcess;
    }

    return urlToProcess;
}

public static boolean isAbsolute(String url){
    if (url.startsWith("//")) { // //www.domain.com/start
        return true;
    }

    if (url.startsWith("/")){ // /somePage.html
        return false;
    }

    boolean result = false;

    try {
        URI uri = new URI(url);
        result = uri.isAbsolute();
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }

    return result;
}

public static String checkUrlStartsWithProtocol(String url) {
    if (!url.startsWith("http://") && !url.startsWith("https://")) {
        StringBuilder prefixBuilder = new StringBuilder();
        prefixBuilder.append("http:");
        if (!url.startsWith("//")) {
            prefixBuilder.append("//");
        }
        url = prefixBuilder.toString() + url;
    }
    return url;
}

public static String extractRootPage(String urlString) {
    int ignoreSlashes = 0;
    if (urlString.startsWith("http://") || urlString.startsWith("https://")) {
        ignoreSlashes = 2;
    }
    int endPosition = urlString.length();
    for (int i = 0; i < urlString.length(); i++) {
        if (urlString.charAt(i) == '/') {
            if (ignoreSlashes == 0) {
                endPosition = i; // substring exclude /
                break;
            } else {
                ignoreSlashes--;
            }
        }
    }
    return checkUrlStartsWithProtocol(urlString.substring(0, endPosition));
}
Ufkoku
  • 2,384
  • 20
  • 44