jsr339-experts@jax-rs-spec.java.net

[jsr339-experts] PLEASE READ: Resolving UriBuilder / WebTarget templates

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Thu, 6 Sep 2012 16:09:56 +0200

Hello experts,

I know it's a long email, but please bear with me. I'd like to propose some changes to the WebTarget and UriBuilder API. Following email provides the rationale as well as the proposal.

Currently we have following methods in the WebTarget:

pathParam(String name, Object value)
pathParams(Map<String, Object> parameters)

Their purpose is to set values to path template variables. E.g.:

client.target("{a}/{b}").pathParam("a", "x") --> "x/{b}"

Also, we have a couple of requests in Jira to provide similar functionality in UriBuilder as well as in general resolve the inconsistencies between WebTarget and UriBuilder URI building API:

http://java.net/jira/browse/JAX_RS_SPEC-211
http://java.net/jira/browse/JAX_RS_SPEC-163

Also there is a Jersey issue filed around inconsistencies/confusion of what WebTarget.getUriBuilder() should return:

http://java.net/jira/browse/JERSEY-1329

So while looking at the WebTarget/UriBuilder consolidation from the larger perspective provided by all these issues, I'd like to propose some changes in these APIs.

First of all, WebTarget.pathParam(s) are misleading method names, since the actual intended purpose of the methods was to resolve a template variable to a value. IOW the expected behavior is:

client.target("{a}").path("{b}").queryParam("a", "{a}").pathParam("a", "x") --> "x/{b}?a=x"

Now I think you're with me, when I say that the name of the pathParam method is misleading. Another issue, perhaps even more interesting is finding the right answer for a question on what should WebTarget.getUriBuilder() return - how should the returned UriBuilder be initialized. For example:

client.target("{a}/{b}").pathParam("a", "x").getUriBuilder()

In this case a few answers are possible for the internal state of the returned UriBuilder:

URI template: "{a}/{b}", internal template values: N/A
URI template: "{a}/{b}", internal template values: "a" -> "x"
URI template: "x/{b}", internal template values: N/A

Now after a careful consideration, I'd argue that we should take approach that corresponds to the answer #3 (even though it may not seem to be the most intuitive answer). IOW, I could not find any practical use case that would support the other 2 options and could not be solvable by 3, but I could find use cases that would only be solvable by #3. One other indication might be that it's hard to find a use case where following makes sense and could be considered as a good practice:

client.target("{a}/{b}").pathParam("a", "x")...pathParam("a", "y")

So my conclusion is that typically you only set a template value only once and once you set it you do want to overwrite it later. E.g.:

authors = client.target("bookstore/authors/{name}");
author = authors.pathParam("name", "Dan Ariely");

... /* somewhere in a different part of app */ ...

books = author.path("books/{name}");
book = books.pathParam("name", "Predictably Irrational");

In the code above the issue with overwriting template values set before is obvious. You certainly do not want to overwrite the author's name with the name of the book.

So finally, here comes my proposal:

remove WebTarget.pathParam(s) methods
introduce new WebTarget.resolveTemplate(s) methods, including method versions that provide flag for "/" encoding in path
introduce new UriBuilder.resolveTemplate(s) methods, including method versions that provide flag for "/" encoding in path

The new resolveTemplate(s) methods would irreversibly resolve the template values in WebTarget or UriBuilder for given template variables, e.g.:

client.target("{a}/{b}").resolveTemplate("a", "x").resolveTemplate("a", "y") --> "x/{b}"
// resolveTemplate("a", "y") above is either ignored or throws IllegalStateException

This proposal should make things consistent. Please provide your feedback ASAP. I'd like to make this change before the PR release planned for next Monday.

Thank you,
Marek