Urin is a free, open source URI generator and parser for Java. It is written to make the dynamic generation of correct URIs easier than with Java’s built-in URI and URL classes, and to provide support for the current URI standard, RFC 3986. Urin has no dependencies. It’s licensed under the Apache 2 License.
The project is The project is hosted on GitHub.
Downloads
Urin is published on Maven Central.
-
Gradle (Kotlin)
-
Gradle (Groovy)
-
Maven
dependencies {
implementation(group = "net.sourceforge.urin", name = "urin", version = "5.2")
}
dependencies {
implemenation group: 'net.sourceforge.urin', name: 'urin', version: '5.2'
}
<dependency>
<groupId>net.sourceforge.urin</groupId>
<artifactId>urin</artifactId>
<version>5.2</version>
</dependency>
Quick start
An HTTPS URI is generated as follows:
String uri = Https.https(
Host.registeredName("www.example.com"),
Path.path("music", "AC/DC", "Back in Black")
).asString();
The uri
variable contains "http://www.example.com/music/AC%2FDC/Back%20in%20Black"
. Note that the /
character in AC/DC
has been encoded as %2F
, and that the space characters in Back in Black
have been encoded as %20
.
The registered name and path could be any Strings we choose; the library will encode them appropriately to the part of the URI where they appear.
To parse the URI we just generated:
var urin = Https.parseHttpUrin("https://www.example.com/music/AC%2FDC/Back%20in%20Black");
List<Segment<String>> segments = urin.path().segments();
The segments
variable contains three Segment
objects, with the values "music"
, "AC/DC"
, and "Back in Black"
.
Usage
Model of URIs and relative references in Urin
The model of URIs and relative references in Urin reflects that defined in RFC 3986. The RFC defines two top level structures:
-
URI - for example http://www.example.com/index
-
Relative reference - sometimes loosely called a relative URI; for example /index.html
These are modelled in Urin as Urin
and RelativeReference
respectively.
These classes provide factory methods that allow any valid URI or relative reference to be generated.
Producing URIs and relative references
Producing a URI is simply a case of calling the relevant factory method on an instance of the Scheme
class, for example:
String uri = Scheme.scheme("ftp").urin(
Authority.authority(Host.registeredName("ftp.is.co.za")),
Path.path("rfc", "rfc1808.txt")
).asString();
The uri
variable contains "ftp://ftp.is.co.za/rfc/rfc1808.txt"
.
It is also possible to generate an instance of java.net.URI
, like so:
URI uri = Scheme.scheme("mailto").urin(
Path.rootlessPath("John.Doe@example.com")
).asUri();
This produces "mailto:John.Doe@example.com"
. Note, however, that java.net.URI
implements the obsoleted RFC 2396, meaning there are certain valid URIs which can be produced using Urin, but which can’t be represented by java.net.URI
.
Generating a relative reference follows the same pattern, for example:
String uri = Scheme.scheme("rsync").relativeReference(
Path.rootlessPath(Segment.dotDot(), Segment.segment("sibling")),
Query.query("some-query")
).asString();
This returns a String containing "../sibling?some-query"
. It is possible to retrieve this as a java.net.URI
in the same way as for a net.sourceforge.urin.Urin
, by calling the asUri()
method. Of note in this example:
-
The path component is created using the
rootlessPath
method, to create a path without a leading/
character. -
The
..
part of the output was generated using thedotDot()
method. This is because..
is being used with the special meaning 'parent', so it shouldn’t be escaped. -
The scheme name doesn’t appear in the output, but the scheme is important because schemes can define modifications to the encoding of other components.
Producing HTTP and HTTPS URIs and relative references
Urin provides specific support for generating HTTP and HTTPS URIs for convenience, and to implement the additional rules and encoding HTTP(S) uses.
These are implemented in the Http
and Https
classes.
For example:
String uri = Http.http(
Host.registeredName("www.example.com"),
Port.port(80),
Path.path("music", "AC/DC", "Back in Black"),
HttpQuery.queryParameters(
HttpQuery.queryParameter("track", "Hells Bells"),
HttpQuery.queryParameter("version", "Radio edit")
),
Fragment.fragment("verse 2")
).asString();
The uri
variable contains "http://www.example.com/music/AC%2FDC/Back%20in%20Black?track=Hells+Bells&version=Radio+edit#verse%202"
. Notice a number of HTTP specific features:
-
The port has been elided because port 80 is the default for HTTP
-
HTTP query parameter separators have been inserted in the query component
-
Spaces in the query component have been encoded as
+
, rather than%20
An equivalent set of methods for generating HTTPS URIs exist on the Https class.
Parsing
The Scheme
class implements parseUrinReference
, parseUrin
, and parseRelativeReference
methods to produce an instances of their respective types from a String
.
For example, we can parse the URI ldap://[2001:db8::7]/c=GB?objectClass?one
as follows:
try {
var parsedUrin = Scheme.scheme("ldap").parseUrin("ldap://[2001:db8::7]/c=GB?objectClass?one");
} catch (ParseException e) {
// handle parse failure
}
ParseException
would be thrown if the String wasn’t a valid URI.
Normalisation
RFC 3986 specifies a number of methods of URI normalisation which are applied by Urin, such as the handling of unnecessary encoding and non-preferred case, and the handling of .
and ..
segments.
For example:
String uri = Http.parseHttpUrin("HTTP://www.example.com/.././some%20pat%68").asString();
The uri
variable contains "http://www.example.com/some%20path"
as a result of normalisation rules having been applied.
Resolution
Relative references can be turned into URIs by resolving them, relative to a context URI.
In Urin, this is achieved using the resolve method on Urin
, for example:
var relativeReference = Http.HTTP.relativeReference(
Path.rootlessPath(Segment.dotDot(), Segment.segment("child-2")),
HttpQuery.queryParameters(HttpQuery.queryParameter("extra-query"))
);
String uri = Http.http(
Authority.authority(Host.registeredName("www.example.com")),
Path.path("child-1")
).resolve(
relativeReference
).asString();
This returns "http://www.example.com/child-2?extra-query"
.
Implementing scheme-specific rules
Urin also provides a mechanism for schemes with extra rules to be implemented, as demonstrated in the Http
class, which handles the non-default encoding of the space character, and the encoding of parameters in the query component of the HTTP scheme.
This is achieved by extending the Query
class.
The source code for HttpQuery
has an example of this in action.
Unusual URIs
Urin is designed to be able to parse and to generate every valid RFC 3986 URI. There are two types of unusual URIs to take note of:
Zero-length first path segment in relative references
URI path segments can encode any Unicode string including the empty string.
An example of a full URI that has empty string as the first segment is http://example.com//foo
.
A relative reference where the first segment is the empty string cannot be represented as e.g. //foo
because RFC 3986 specifies that the leading //
indicates this should be interpreted as a relative reference to the authority foo
(i.e. if //foo
is resolved against http://example.com
, the result is http://foo
).
A relative reference where the first segment is the empty string can, however, be written by taking advantage of the dot segment, e.g. /.//foo
.
Urin automatically uses this technique where required.
First query parameter with zero-length name and no value in HTTP(S) URIs
The optional query part of HTTP(S) URIs is composed of zero or more query parameter names, each with an optional value.
The parameter name (and for that matter, the parameter value), can encode any Unicode string, including the empty string, so, for example, the URI http://example.com?&foo
has two valueless parameters named ""
[the empty string, from between the ?
and the &
], and "foo"
.
It is (implicitly) not possible to write URIs with a single valueless query parameter named empty string because they would be indistinguishable from URIs with zero query parameters, so, for example http://example.com?
might erroneously be interpreted as having a single valueless query parameter named ""
, but in fact has a query consisting of zero query parameters.
Recognising this, Urin normalises queryParameters(queryParameter(""))
to queryParameters()
to make comparison of Urin objects consistent with their URI representation.
Further details
In-depth details of the API are available in the online javadoc.