Earthly Powers
- All
- Fast Infoset
- General
- Java
- REST
Building URIs
At first sight building URIs using Java SE appears deceptively simple. Beware!
Say for example i have an instance of java.net.URI, baseUri, that is the following:
"http://localhost:8080/base"
and i want to append the following relative path to that URI:
"a:b;param=matrix/hello world"
such that i would like my URI to be:
"http://localhost:8080/base/a:b;param=matrix/hello%20world"
It is not possible to create a URI with the relative path like this:
new URI("a:b;param=matrix/hello world");
new URI(null, null, "a:b;param=matrix/hello world", null);
because, in the first case, there is an illegal character, the space character in "hello world", and therefore resorting to string concatenation will also result in an invalid URI:
baseUri.toString() + '/' + "a:b;param=matrix/hello world"
Further more, for both cases java.net.URI correctly assumes the "a:" is a scheme (although it gets very confused about the rest of the URI!).
We could do this:
uri = baseUri.resolve(
new URI(null, null, "/a:b;param=matrix/hello world", null);
but because a '/' is prefixed to the path we will loose the path of baseUri. [Update: the path of baseUri will be lost regardless of prefixing because it does not end with a '/']
The only reliable way of doing this using java.net.URI is if a new URI is created from the components of baseUri:
URI u = new URI(base.getScheme(),
base.getUserInfo(), base.getHost(), base.getPort(),
base.getPath() + "/a:b;param=matrix/hello world",
base.getQuery(), base.getScheme());
What a PITA! If the baseUri was "http://localhost:8080/base/" then i would end up with two '/' in between the base path and the appended path so in general i should ensure that only a single '/' occurs.
This is why the JSR-311 expert group is specifying the UriBuilder class as part of JAX-RS so you can do this:
UriBuilder.fromUri(baseUri).
path("a:b;param=matrix/hello world").build();
or if i would like to be explicit about the matrix parameters:
UriBuilder.fromUri(baseUri).
path("a:b").
matrixParam("param", "matrix").
path("hello world").build();
to create the desired URI intuitively and safely.
UriBuilder also supports URI templates so i could do:
UriBuilder.fromUri(baseUri).
path("a:{p1}").
matrixParam("param", "{p2}").
path("hello {p3}").build("b", "matrix", "world");
You can find an implementation of UriBuilder in the latest build of Jersey. however, since we have yet to pull in the latest 311 API into Jersey i have made a clone you can find it at com.sun.ws.rest.api.core.UriBuilder if you want to have a play.
Posted at 04:08PM Aug 31, 2007 by Paul Sandoz in REST | Comments[0]