3

I'm trying to find a Java library for all-purpose URI/URL extraction and manipulation, like I've seen in many other languages.

So much java code I've seen uses manual string split/join/concatenation, with the occasional URLEncoder.encode()/URLDecoder.decode(). And this leads to unsafe code.

I thought the two contenders were Spring's UriComponentsBuilder and apache's URIBuilder. But I don't see that either of these two allow me to extract a query parameter from a URL, which is such a common use-case.

I'm trying to do the Java equivalent of this Javascript:

let url = new URL("http://foobar/path")
url.searchParams.set("param1", "a=b")

// See that it gets encoded properly as param1=a%3Db
console.log(url)
// prints: http://foobar/path?param1=a%3Db

// And decoded properly again as a=b
console.log(new URL(url.toString()).searchParams.get("param1"))
// prints: "a=b"

UriComponentsBuilder has a build().getQueryParams().getFirst("param1") method for it, but it doesn't decode the parameter, and URIBuilder requires me to search through a list of parameters myself - not the handiest API.

I'm shocked that I can't find a single Java library that provides all the common extraction and manipulation methods for URL strings. Have I missed something?

Here is some test code demonstrating my findings:

package javademo;

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URISyntaxException;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

public class TestUriComponents {
    @Test
    public void testUriComponentsBuilder() {
        assertEquals("a", "a");
        UriComponentsBuilder builder;

        // Lets build a string with a parameter value of a=b (that needs encoding)
        builder = UriComponentsBuilder.fromHttpUrl("http://foobar/path");
        builder.queryParam("param1", "a=b");
        String encodedURL = builder.build().encode().toUriString();
        System.out.println(encodedURL);

        // Now lets extract param1 from that URL again
        builder = UriComponentsBuilder.fromHttpUrl(encodedURL);
        UriComponents components = builder.build().encode();

        // This **fails**. getQueryParams() does not decode the values... Really???
        assertEquals("a=b", components.getQueryParams().getFirst("param1"));
        // This does pass, however (but is never reached)...
        assertEquals("a%253Db", components.getQueryParams().getFirst("param1"));
    }

    @Test
    public void testURIBuilder() throws URISyntaxException {
        URIBuilder builder = new URIBuilder("/foobar/path");
        builder.addParameter("param1", "a=b");
        String encodedURL = builder.build().toString();
        System.out.println(encodedURL);
        builder = new URIBuilder(encodedURL);

        // Really? I have to search the list myself? Really???
        List<NameValuePair> queryParams = builder.getQueryParams();
        for (NameValuePair qp : queryParams) {
            System.out.println(String.format("%s: %s", qp.getName(), qp.getValue()));
            if (qp.getName().equals("param1"))
                assertEquals("a=b", qp.getValue());
        }
    }
}
Peter V. Mørch
  • 13,830
  • 8
  • 69
  • 103

0 Answers0