If you’re like me you really like the new Servlet 3.0 spec that allows for annotated servlet classes. This approach along with the new ServletContainerInitializer interface potentially allows for code-based application configuration and deployment without an application deployment descriptor (web.xml) file.
One thing lacking in the new spec’s annotations, is the ordering of the filter chain. This, IMO, is REALLY important. It allows the developer to ensure encoding filters or other types of “must happen first” filters are ahead of other filters in the chain. While the documentation states when using annotated filter classes the order is undetermined, my tests have shown the order is the order in which they appear in the class path. If all your annotated filter classes are in one package and named according to order (AFilter.class, BFilter.class, CFilter.class), then there is no problem. But this is unlikely. Also, libraries often come with non-annotated filter classes which must be programmatically included in the filter chain, or added via the web.xml file.
I have found I can annotate my classes – have them anywhere on the class path – and STILL achieve ordering by specifying only the class names in the web.xml file. The following is an example of how to order two annotated Servlet 3 filters that are on the class path:
In my tests – this properly orders the filter chain so ZFilter is before AFilter. If there was another annotated filter class on the class path and NOT part of this mapping, it would be AFTER the filters in this mapping. E.g., ZFilter,AFilter, SomeOtherFilter. Removing these mappings returns the order to class path ordering: AFilter,SomeOtherFilter, ZFilter.
This approach allows one to embrace the new servlet spec – and have minimal configuration in the web.xml. Theweb.xml would also be used to set up non-Servlet 3 filters (E.g., Filters provided by libraries).
If you are pragmatically adding filters to the context in a ServletContainerInitializer then the order you add the filters is maintained – and the isMatchAfter parameter is honored.
.addMappingForUrlPatterns(null, true, “/*”);
I have found I can use a combination of all three approaches, but understanding the order of operations is important:
- Ordering of web.xml definitions are processed first.
- Other annotated filters NOT in the web.xml will be NEXT in the chain.
- Filters added via the ServletContext addFilter() method are processed last, AND the value ofisMatchAfter is honored. So you can add a filter using this method, and place it FIRST or NEXT in the filter chain.
Check the spec section 8.2 and add the bits you need to your web.xml or web-fragment.xml, depending on your packaging. Note these are
In a web.xml you can filters and listeners by name:
<absolute-ordering> <name>FirstFilter</name> <name>NextFilter</name> </absolute-ordering>
In a web-fragment.xml you can filters and listeners before or after others as specified by name or generically with the “others” tag. For example, to try to order your JAR first, use the following in the web-fragment.xml
<order> <before> <others/> </before> </order>
Note that the web-fragment.xml orders for the JAR, and filters or listeners within the same JAR are arbitrarily ordered, unless specified in the application’s web.xml.