users@jax-rs-spec.java.net

[jax-rs-spec users] [jsr339-experts] Re: HEADS-UP, IMPORTANT: Problems with JAX-RS interceptors

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Thu, 26 Apr 2012 15:52:57 +0100

Hi

Please see comments at the end of the message
On 26/04/12 13:29, Marek Potociar wrote:
> Hello all,
>
> As we started to look more closely into implementing support for JAX-RS
> Interceptors API in Jersey, we ran into several major issues. It seems,
> that there are serious questions around the interaction between filters
> and interceptors. This is IMO to a large extend caused by the
> functionality overlap between the interceptors and filters (applies to
> both filtering API proposals - the old one as well as the new one).
>
> A very brief summary of the concept: Interceptors form a wrapping chain
> and are supposed to intercept calls to entity providers (MBR/MBW)
> whenever the entity is read or written either by the client, resource
> method or a filter. Filters form an un-wrapping chain and filter every
> request and response send or received. Unfortunately, it seems that the
> two concepts just don't work well together the way they are designed.
>
> Here is the list of the issues and open questions that we identified so far:
>
> 1. Name-bound interceptors seem to clash with pre-matching filters.
> If a pre-matching filter will try to manipulate the entity, the
> name-bound interceptors would not get invoked, which may be fatal
> (see Example 1).
> 2. The generic type information on the interceptor seems redundant.
> It is not clear what should the runtime do when an interceptor is
> configured for a type that it does not support in it's generic
> type declaration.
> 3. The reader interceptors are now not restricted in any way wrt.
> changing the returned entity Java type to a type that is
> incompatible with the Java type requested by the caller (either
> JAX-RS runtime or an interceptor up in the chain). Changing the
> type of the returned entity in a non-compatible way seems to
> always have fatal consequences as, by definition, the caller
> expects to receive the original type it asked for.
> 4. Filters may un-intentionally corrupt the entity stream in
> applications configured asymmetrically wrt. interceptors (see
> Example 2)
>
>
> A couple of examples to demonstrate the issues:
>
> * /Example 1: //Interceptors interfere with filters reading/writing
> entity - named interceptors/
>
> /
> /
> /
> Suppose the successful reading requires a special named interceptor
> attached to a resource method.
> How do we guarantee that the entity can be read in a pre-matching
> filter?
> /
> /
> /
>
> * /Example 2: Interceptors interfere with filters reading/writing
> entity - asymmetrical configuration/
>
>
> Suppose a filter wants to replace an entity using writeEntity
> method. Suppose a special (inbound) reader interceptor is configured
> in the interceptor chain (e.g. signature verifier), but there is no
> (outbound) writer interceptor counterpart (e.g. signature appender).
> How do we guarantee that the entity written by the filter will be
> readable again? Note that not having a corresponding outbound
> (signature appender) interceptor configured for the request is a
> valid and justifiable use case. Even worse, the corresponding
> outbound functionality can be, in general, provided by an outbound
> filter instead of an interceptor, which will obviously not get
> invoked as part of the writeEntity method.
>
>
> We haven't found any reasonable way to resolve the outlined issues
> without changing the API. Here are couple of options for a solution we
> can see:
>
> * /Option 1/
> o interceptors should not be typed, should be stream focused -
> i.e. could be renamed to Input/OutputStreamInterceptors
> + people should use MBW and/or filters for entity
> type-dependent manipulation
> o interceptors should only be global (as they may need to be
> invoked in the pre-matching phase)
> o interceptors should be executed just once per
> request/response when reading from/writing to the wire, not
> for intermediate transformations (hence calling it MBW
> interceptors may be misleading)
> o filters should work with entities (decoded) - with one
> possible kind of entity being a stream
> + drop the get/setEntityStream methods as redundant (or
> keep them just as convenience shortcuts for
> read/writeEntity counterparts)
>
> Option 1 seems to allow the interceptors to be reused between client and
> server side. But not sure if this is not only useful in a very limited
> set of use cases (e.g. real life may show that in most cases a server
> and client-side implementation may need to be separate anyway due to the
> need of attaching/checking different headers on the client side than on
> the server side etc.).
>
> * /Option 2/
> o completely remove interceptors, have just filters
> o filters are more versatile and can wrap the input/output
> stream by the way of calling get/setEntityStream() - which
> covers the functionality separated out into interceptors
>
> Option 2 stream-lines the API and makes it easier to understand by the
> end user as it removes the need to take the two different concepts into
> account when writing a filter or interceptor or make decisions about
> whether the intended functionality belongs to a filter or an interceptor
> or a combination of the two.

This option2 seems like a good candidate. I'm a bit confused at the
moment by the necessity to have MBRs & MBWs (basic interceptors,
especially MBWs which can update the response headers), filters and
interceptors. Having only in/out filters on client/server sides, in
addition to existing MBRs and MBWs seems ideal, assuming it is possible
to refactor filters such that can also manage what interceptors can do now.

I'll try to provide a more specific feedback in the next few days,

Cheers, Sergey

>
> Please, let us know what is your preferred solution for the issues. We
> need your feedback ASAP as we plan to postpone the EDR3 release a week
> or two so that we can release a solid filtering API proposal.
>
> Thank you.
>
> Marek & Santiago