users@jax-rs-spec.java.net

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

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Fri, 23 Dec 2011 10:36:35 +0000

Markus, this summary was helpful. let me comment below,

On 22/12/11 13:28, Markus KARG wrote:
>>> 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()).
>
I have another one in mind,

>> 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.
>

I think now it is a spec (limited to the java doc of UriBuilder), more
on it below

> (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.
>

The situation with path(Class) is completely different ? The case where
we are reading from the legacy DB is about submitting the values we do
not control to UriBuilder. We are in control when annotating the
resource classes.

> (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)).
>
I guess I'm really slow,

What happens if I do segment("a/x/c") and pass 'false' ? Guess we should
get "a/x/c" as this boolean applies to template vars, right ?
How about
segment("{x}") and false, should not we get "a%2Fx%2Fc" ?

> Hope that you see the simplicity in this new overload?
>

I see better why you and Marek see it improving the situation. I won't
rush with my final conclusion this time, but so far what I see is that
when we have a case where

we do path("{a}") and seeing the substitution value (say a key read from
the legacy data source and similar) still containing "/" then we are
simply doing a wrong code, we should be doing

segment("{a}")

Thanks, Sergey

> Regards
> Markus
>


-- 
Sergey Beryozkin
Talend Community Coders
http://coders.talend.com/
Blog: http://sberyozkin.blogspot.com