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
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
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
* /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
* /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
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
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.
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.
Marek & Santiago
[jsr339-experts] Re: HEADS-UP, IMPORTANT: Problems with JAX-RS interceptors