La seule solution serait que vous consommiez vous-même l'intégralité du flux d'entrée dans le filtre, que vous preniez ce que vous voulez, puis que vous créiez un nouvel InputStream pour le contenu que vous lisez, et que vous mettiez cet InputStream dans un ServletRequestWrapper (ou HttpServletRequestWrapper).
L'inconvénient est que vous devrez analyser vous-même la charge utile, la norme ne vous offrant pas cette possibilité.
Addenda --
Comme je l'ai dit, vous devez vous pencher sur HttpServletRequestWrapper.
Dans un filtre, vous continuez en appelant FilterChain.doFilter(request, response).
Pour les filtres triviaux, la requête et la réponse sont les mêmes que celles passées au filtre. Ce n'est pas forcément le cas. Vous pouvez les remplacer par vos propres demandes et/ou réponses.
HttpServletRequestWrapper est spécifiquement conçu pour faciliter cela. Vous lui passez la requête originale, et vous pouvez ensuite intercepter tous les appels. Vous créez votre propre sous-classe et remplacez la méthode getInputStream par la vôtre. Vous ne pouvez pas modifier le flux d'entrée de la requête originale, donc à la place, vous avez ce wrapper et retournez votre propre flux d'entrée.
Le cas le plus simple est de transformer le flux d'entrée des requêtes originales en un tampon d'octets, d'effectuer toutes les opérations magiques que vous souhaitez, puis de créer un nouveau flux d'entrée ByteArrayInputStream à partir de ce tampon. C'est ce qui est renvoyé dans votre wrapper, qui est transmis à la méthode FilterChain.doFilter.
Vous devrez sous-classer ServletInputStream et créer un autre wrapper pour votre ByteArrayInputStream, mais ce n'est pas un problème non plus.