29

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.

4
  • 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? Commented Dec 8, 2010 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." Commented Dec 8, 2010 at 18:14
  • Be aware URL uses your network connection Commented Dec 8, 2010 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. Commented Dec 8, 2010 at 18:22

4 Answers 4

53

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.

Sign up to request clarification or add additional context in comments.

6 Comments

This doesn't appear to work with Protocol Urls (urls like //). You can try it out at IDEOne
which can be used to do absolute redirects, like in this example
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 URI.create
@Abhijit Sarkar you should post this as an answer (else I will do :p) I would vote for you!
|
4

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

Comments

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
        }
    }
}

3 Comments

This is not a correct solution. http/foo.html is a relative URL pointing to the html subdirectory but your code would think it is absolute.
how would your solution look like @StephenOstermiller?
Other answers here use URL.isAbsolute() and that looks like a fine solution to me.
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));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.