users@jax-rs-spec.java.net

[jax-rs-spec users] [jsr339-experts] Re: Re: HEADS-UP: Encoding values of UriBuilder template parameters

From: Markus KARG <markus_at_headcrashing.eu>
Date: Thu, 22 Dec 2011 14:28:33 +0100

> > A JavaDoc change is all I asked for (while I would really love to see
> > the API work as I proposed, instead). :-) But note that segment() is
> > currently NOT able to encode slashes in JAX-RS 1.0, as I wrote you
> > privately before, so to get %2F one must actually encode this
> MANUALLY
> > at the moment (I want to get rid of String.ReplaceAll)! So
> technically
> > spoken, you won't break too much anyways. ;-)
>
> Is it a spec issue or a specific implementation issue ?

I have not found something in the spec explaining this behaviour, but I
think Marek can describe the issue better than me. I just detected it in
need of getting %2F without doing String.ReplaceAll("/", "%2F") all the
time.

> I'm really sorry if I'm showing my ignorance here. I'm finding it
> difficult and daunting to figure out from this thread why the need for
> the new build overload is needed, Please, for my benefit as well as for
> the benefit of others who may've not followed this thread, give 2
> examples demonstrating

The need is simple to explain: You want JAX-RS to invoke a URL which is made
up from a template. The template contains a paramter to extend the path with
the ID of a record (like a database primary key). The actual value is passed
by .build(value). It can happen that the value contains a forward slash, for
example in legacy databases where the PK is made up of a string. So the
slash must get encoded as %2F. If you don't do that, the JAX-RS resource's
@Path("{id}") will not match. This cannot get fixed due to backwards
compatiblity. So there are only two valid solutions: (a) Marek's proposal of
an additional boolean telling the implementation whether to use encoding or
not. (b) Adding a second method with a different name that implies encoding
always (like .encodeAndBuild()).

> 1. The combination of segment() and path() is not enough to resolve
> unambiguously the issue of encoding template parameters

(a) Actually .path("a/b").segment("{x}").build("c/d") actually renders as
"a/b/c/d", but must render to "a/b/c%2Fd" (see above). Current you need
String.ReplaceAll("/", "%2F") to make it work, which is nasty.

(b) Try to get %2F with .path(Class) or .path(Class, String) without writing
tons of reflection code. There just is no .segment(Class) or .segment(Class,
String) to solve this.

(c) As described earlier in depth, segment is defined in the RFC as a part
of the path element (not as something different to path), so without
improved JavaDocs people will not assume to find different encoding rules
for .path() and .segment(). It is counterintuitive that it is up to the
*declaration* method how the encoding works like, as people are used to
other templating mechanisms like JDBC where this plays no role (it ALWAYS
encodes data, even if not necessary, as people could fill in unencoded
values by .path(variable) instead of .path("{x}").build(variable) -- which
is much more straightforward).

> 2. What happens with builder.segment("{bar}").path("{foo}") and a value
> 'true' passed to a new overload, where a "{bar}" substitution will also
> contain "/" characters. I feel at the moment that given that both
> segment() and path() operate on the same URI component this extra flag
> will confuse people like me at least a lot

As 'true' means 'always encode all values' it will enforce complete
encoding. You will get %2F for each slash in both, the values for bar and
foo.

Rule: As long as you pass 'true' to the new overload, you can simply pass
variables to .segment() and .path() to get slashes ALWAYS, and simply pass
variables to .build() to get %2F ALWAYS. This rule is much simpler to
understand than the current (default, 'false') behaviour. Nothing to think
really. Just pass 'true' and decide whether you want slashs (-->
.segment(x), .path(x)) or your want %2F --> .build(x)).

Hope that you see the simplicity in this new overload?

Regards
Markus