user3573403
user3573403

Reputation: 1822

Order of JAX-RS filter and interceptor

I have two request filters and one request interceptor as follows:

@Provider
@RequestLogger
@Priority(100)
public class LogRequestFilter implements ContainerRequestFilter {
    ...
}

@Provider
@OracleSessionChecker
@Priority(300)
public class CheckOracleSessionFilter implements ContainerRequestFilter {
    ...
}

@Provider
@RequestChecker
@Priority(200)
public class CheckRequestInterceptor implements ReaderInterceptor {
    ...
}

I have JAX-RS web services that use these filters and interceptor. The following is one example web service method.

@POST
@RequestLogger
@RequestChecker
@OracleSessionChecker
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("Logout")
public Response logout(@Context HttpServletRequest request, Parameters inputs) {
    ...
}

From the priorities given, I would think that the order that the filters/interceptor are called would be: LogRequestFilter, CheckRequestInterceptor, CheckOracleSessionFilter.

But the actual order that they are called is: LogRequestFilter, CheckOracleSessionFilter, CheckRequestInterceptor.

Why is the CheckRequestInterceptor called last even though its priority, 200, is in the middle?

How can I make them called in the order that I want (that is, LogRequestFilter, CheckRequestInterceptor, CheckOracleSessionFilter)?

Thanks in advance.

Upvotes: 4

Views: 6970

Answers (2)

DJDaveMark
DJDaveMark

Reputation: 2855

All RequestFilters are executed based on their priorities before any RequestInterceptors (which are then executed based on their priorities).

The simplest explanation I can think of is if you had the following files in a folder:

F-100
F-300
I-200

I-200 doesn't come before F-300 (even though 200 is before 300) because 'F's are sorted before 'I's.

Upvotes: 5

dur
dur

Reputation: 17009

You can't mix filter and interceptor execution order, see Jersey Documentation:

10.4. Filter and interceptor execution order

Let's look closer at the context of execution of filters and interceptors. The following steps describes scenario where a JAX-RS client makes a POST request to the server. The server receives an entity and sends a response back with the same entity. GZIP reader and writer interceptors are registered on the client and the server. Also filters are registered on client and server which change the headers of request and response.

  1. Client request invoked: The POST request with attached entity is built on the client and invoked.
  2. ClientRequestFilters: client request filters are executed on the client and they manipulate the request headers.
  3. Client WriterInterceptor: As the request contains an entity, writer interceptor registered on the client is executed before a MessageBodyWriter is executed. It wraps the entity output stream with the GZipOutputStream.
  4. Client MessageBodyWriter: message body writer is executed on the client which serializes the entity into the new GZipOutput stream. This stream zips the data and sends it to the "wire".
  5. Server: server receives a request. Data of entity is compressed which means that pure read from the entity input stream would return compressed data.
  6. Server pre-matching ContainerRequestFilters: ContainerRequestFilters are executed that can manipulate resource method matching process.
  7. Server: matching: resource method matching is done.
  8. Server: post-matching ContainerRequestFilters: ContainerRequestFilters post matching filters are executed. This include execution of all global filters (without name binding) and filters name-bound to the matched method.
  9. Server ReaderInterceptor: reader interceptors are executed on the server. The GZIPReaderInterceptor wraps the input stream (the stream from the "wire") into the GZipInputStream and set it to context.
  10. Server MessageBodyReader: server message body reader is executed and it deserializes the entity from new GZipInputStream (get from the context). This means the reader will read unzipped data and not the compressed data from the "wire".
  11. Server resource method is executed: the deserialized entity object is passed to the matched resource method as a parameter. The method returns this entity as a response entity.
  12. Server ContainerResponseFilters are executed: response filters are executed on the server and they manipulate the response headers. This include all global bound filters (without name binding) and all filters name-bound to the resource method.
  13. Server WriterInterceptor: is executed on the server. It wraps the original output stream with a new GZIPOuptutStream. The original stream is the stream that "goes to the wire" (output stream for response from the underlying server container).
  14. Server MessageBodyWriter: message body writer is executed on the server which serializes the entity into the GZIPOutputStream. This stream compresses the data and writes it to the original stream which sends this compressed data back to the client.
  15. Client receives the response: the response contains compressed entity data.
  16. Client ClientResponseFilters: client response filters are executed and they manipulate the response headers.
  17. Client response is returned: the javax.ws.rs.core.Response is returned from the request invocation.
  18. Client code calls response.readEntity(): read entity is executed on the client to extract the entity from the response.
  19. Client ReaderInterceptor: the client reader interceptor is executed when readEntity(Class) is called. The interceptor wraps the entity input stream with GZIPInputStream. This will decompress the data from the original input stream.
  20. Client MessageBodyReaders: client message body reader is invoked which reads decompressed data from GZIPInputStream and deserializes the entity.
  21. Client: The entity is returned from the readEntity().

It is worth to mention that in the scenario above the reader and writer interceptors are invoked only if the entity is present (it does not make sense to wrap entity stream when no entity will be written). The same behaviour is there for message body readers and writers. As mentioned above, interceptors are executed before the message body reader/writer as a part of their execution and they can wrap the input/output stream before the entity is read/written. There are exceptions when interceptors are not run before message body reader/writers but this is not the case of simple scenario above. This happens for example when the entity is read many times from client response using internal buffering. Then the data are intercepted only once and kept 'decoded' in the buffer.

Upvotes: 3

Related Questions