That kind of abstraction would be useful for handling any kind of cross-cutting concerns, similar to aspects.
For example, I might want all my filters to log that they are being applied to the request and then log any exceptions that passed by them so that I can know for any given request which filters acted on it. To put the exact same logging code in all of my filters would be a violation of DRY. To try and hook aspects into filters would be overly complicated. I cannot think of a better way than inheritance to achieve that goal.
Another example is that I might have a set of filters which are only applied to certain users or types of requests. A simple base filter class which had an abstract getUsersToApplyFor()
would make that very easy to implement.
What I would NOT use this approach for is to setup custom filter chains through inheritance. For example, I would not create a base class which modified the request and response in one way and a child class which then additionally modified the request and response in another way, and the two modifications are unrelated to each other. As you pointed out, that would be better left in the web.xml where it would be clearer for future developers.