users@jax-rs-spec.java.net

[jax-rs-spec users] [jsr339-experts] Re: HEADS-UP: ParamConverter API issues.

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Thu, 11 Oct 2012 10:23:43 +0100

Hi,
On 10/10/12 17:01, Marek Potociar wrote:
> Hi all,
>
> when implementing the support for ParamConverter and
> ParamConverterProvider we found some unclear points I'd like to discuss
> with you:
>
> *1. HeaderDelegate vs. ParamConverter priority*
> ParamConverter is documented to work also for header parameters, which
> clashes with existing JAX-RS HeaderDelegate concept. We may either
> decide to not support ParamConverters in case of header value conversion
> or we need to define the resolution priorities. The suggestion is to
> define following priority-based resolution algorithm for header data
> conversion:
>
> 1. Custom (user supplied) ParamConverter (not null ParamConverter
> returned from ParamConverterProvider)
> 2. Implementation specific HeaderDelegate
> 3. Implementation specific ParamConverter
>

Is HeaderDelegate supposed to be called directly by the runtime ?

IMHO it would be much simpler to state that if a particular
HeaderDelegate implementation want to act as ParamConverter then let it
implement ParamConverterProvider

> Also, a HeaderDelegate could extend from ParamConverter as the APIs are
> essentially identical.
> *
> 2. ParamConverter used in ResponseBuilder (as defined by current javadoc)*
> The problem is that a ResponseBuilder instance is created via
> RuntimeDelegate, which is not application scoped, but is shared among
> all application. As such, the RuntimeDelegate instance has no access to
> application providers. (Btw. I'm wondering whether any of your
> implementations does provide access to application providers in your
> RuntimeDelegate impl.) This means the application level providers cannot
> be passed to the response builder instance being created. Consequently,
> when the user calls Response#getStringHeaders() on the built response,
> some of the passed headers may not be convertible, e.g.:
>
> // cannot use ParamConverter to convert MyBean instance.
> Response.ok().header("response-header", new
> MyBean("header")).build().getStringHeaders();
>
> One solution (although not the most elegant) would be to document that
> ParamConverter will not convert headers passed into Response (only
> toString() will be called on them). However, header parameters passed in
> ContainerResponseFilter or WriterInterceptor will still be convertible.
> For example, assume a registered ParamConverter<MyBean> on the server
> (using MyBeanParamConverterProvider) and the following resource method
>
> @GET
> public Response get() {
> Response response = Response.ok()
> .header("response-header", new MyBean("header"))
> .build();
>
> // the code bellow would fail.
> response.getHeaderString("response-header");
>
> ...
>
> return response;
> }
>
> ...which returns a response processed by a response filter:
>
> public static class MyFilter implements ContainerResponseFilter {
>
> @Override
> public void filter(ContainerRequestContext requestContext,
> ContainerResponseContext responseContext) {
>
> // the code bellow would pass.
> response.getHeaderString("response-header");
>
> ...
> }
> }
>
> The above looks a bit inconsistent which is why I'm mentioning it.
> Obviously, the any Response instance returned as a result of a the
> client-side request invocation will have access to application providers
> and as such the conversion would work fine.
>

I'd propose to limit the scope of where ParamConverters can be applied,
specifically they can only be applied when populating the (method)
request parameters

> *3. WebTarget vs. UriBuilder*
>
> The API docs defines that ParamConverters are supported in the Client
> API. IOW, any parameters passed to WebTarget (headerParam, queryParam,
> resolveTemplate, ...) but also parameter values passed by
> resolveTemplate should be convertible using the available
> ParamConverters configured in the WebTarget's configuration. Note
> however, that while WebTarget and UriBuilder share similar interface,
> the parameter conversion would work only in WebTarget instance and not
> in an arbitrary UriBuilder instance directly as UriBuilder (akin to
> ResponseBuilder) is created by a RuntimeDelegate instance and as such is
> not bound to a specific application runtime. Only UriBuilder instances
> returned by WebTarget may be capable of using ParamConverters (albeit
> UriBuilder documentation specifically talks only about calling
> toString() method in these cases).
>
> So the question is whether we should support ParamConverters in
> UriBuilder instances created by a WebTarget, or not:
>
> final WebTarget target = /... some web targe/t
> target.queryParam("a", new MyBean("aaa")); // works using ParamConverters
>
> UriBuilder uriBuilder = target.getUriBuilder();
> uriBuilder.queryParam("b", new MyBean("bbb")).build(); // may work using
> ParamConverters
>
> UriBuilder.fromPath(...)..queryParam("c", new MyBean("ccc")).build() //
> will only use MyBean.toString()
>
> I think the inconsistency illustrated in the example above is obvious,
> which may be confusing to JAX-RS users. Not sure however how to address
> it. A possible way would be to try to make the RuntimeDelegate instances
> bound to applications. But that would be quite complicated. In any case,
> we need to find a clean solution. If we're not able to find one at the
> moment, we should perhaps postpone introduction of the ParamConverter API.
>
IMHO trying to get ParamConvertes applicable at different API levels
complicates things a lot.

Sergey

> Any thoughts or ideas?
>
> Thanks,
> Marek