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());
}
}
}