Using Tomcat, @WebFilter doesn't work with <filter-mapping> inside web.xml

10,633

Solution 1

It's a bug in Tomcat 7. I reported it as issue 53354.

As it's not possible to specify the invocation order in a @WebFilter, users are forced to explicitly specify <filter-mapping> in web.xml. This works in combination with a @WebFilter(filterName) in Glassfish and JBoss AS as follows:

@WebFilter(filterName="filter1")
public class Filter1 implements Filter {}

@WebFilter(filterName="filter2")
public class Filter2 implements Filter {}

with

<filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/url1/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/url2/*</url-pattern>
</filter-mapping>

However it fails in Tomcat 7.0.27 with the following confusing exception (the <url-pattern> is been set)

Caused by: java.lang.IllegalArgumentException: Filter mapping must specify either a <url-pattern> or a <servlet-name>
    at org.apache.catalina.core.StandardContext.validateFilterMap(StandardContext.java:3009)
    at org.apache.catalina.core.StandardContext.addFilterMap(StandardContext.java:2968)
    at org.apache.catalina.deploy.WebXml.configureContext(WebXml.java:1207)
    at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1294)
    at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:855)
    at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:345)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5161)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    ... 7 more

In the meanwhile your best bet is to use Glassfish or JBoss AS instead, or to register the filters by <filter> anyway.

Solution 2

You must specify a target for the Servlet Filter. Either provide a value for 'servletNames' or 'urlPatterns'.

http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebFilter.html

e.g.

@WebFilter(filterName="mustBeSignedInFilter", urlPatterns={ "/signed/in/path/*" })
public class MustBeSignedInFilter implements Filter
Share:
10,633

Related videos on Youtube

AndrewBourgeois
Author by

AndrewBourgeois

Updated on October 12, 2022

Comments

  • AndrewBourgeois
    AndrewBourgeois over 1 year

    Here's a working web.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0">
    
        <session-config>
            <session-timeout>30</session-timeout>
        </session-config>
    
         <filter>
            <filter-name>rememberMeCookieFilter</filter-name>
            <filter-class>be.example.fun.jsp.filters.RememberMeCookieFilter</filter-class>
        </filter>
    
        <filter>
            <filter-name>mustBeSignedInFilter</filter-name>
            <filter-class>be.example.fun.jsp.filters.MustBeSignedInFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>rememberMeCookieFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <filter-mapping>
            <filter-name>mustBeSignedInFilter</filter-name>
            <url-pattern>/private/*</url-pattern>
        </filter-mapping>
    </web-app>
    

    When I remove the <filter> elements and use the following annotations instead:

    @WebFilter(filterName="rememberMeCookieFilter")
    public class RememberMeCookieFilter implements Filter
    
    @WebFilter(filterName="mustBeSignedInFilter")
    public class MustBeSignedInFilter implements Filter
    

    Then Tomcat 7.0.14 gives me the following error:

    java.lang.IllegalArgumentException: Filter mapping must specify either a <url-pattern> or a <servlet-name>
        at org.apache.catalina.core.StandardContext.validateFilterMap(StandardContext.java:2956)
        at org.apache.catalina.core.StandardContext.addFilterMap(StandardContext.java:2915)
        at org.apache.catalina.deploy.WebXml.configureContext(WebXml.java:1180)
        at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1270)
            ...
    

    I followed the answer of this question, but that doesn't work for me.

    Here are the dependencies of my web application:

    <dependencies>
            <!-- SLF4J (+ LOGBack) for logging -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.6.4</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.0.0</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.codehaus.groovy</groupId>
                <artifactId>groovy</artifactId>
                <version>1.8.3</version>
            </dependency>
    
            <!-- The servlet API that I installed in my local repo -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0</version>
                <type>jar</type>
                <scope>provided</scope>
                <!--optional>false</optional-->
            </dependency>
    
            <!-- JUnit for testing -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.8.2</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    

    EDIT: I only have the issue when using Tomcat (7.0.14). Glassfish is fine.

  • AndrewBourgeois
    AndrewBourgeois almost 12 years
    I'm only removing the <filter> elements from my web.xml, not the <filter-mapping> elements. As answered in the following question, it should work: stackoverflow.com/questions/6560969/…. It only works when I deploy it in a Glassfish environment.
  • AndrewBourgeois
    AndrewBourgeois almost 12 years
    I'm OK with using <filter> elements as I'm doing this for my own learning. Why is it that this issue was only dicovered now? Servlet 3.0 has been out for a while, Tomcat 7 too, and this is a very basic feature... (I only just started learning servlets). Did people abandon Filters for something else or ...?
  • BalusC
    BalusC almost 12 years
    No idea. Maybe because people were not aware about this. Or maybe because the ordering didn't matter for them. Or maybe because they didn't use Tomcat for their not-so-small webapps with multiple filters for which ordering matters. Or maybe because they didn't find it worth the effort reporting. Etc. Who knows.
  • BalusC
    BalusC almost 12 years
    FYI: has been fixed by Mark some secs ago. Will be in 7.0.28 and onwards.
  • AndrewBourgeois
    AndrewBourgeois over 11 years
    When using JBoss AS 7.1 I need to use "metadata-complete="false"" to avoid this very same issue. Do you happen to know why JBoss and Tomcat behave differently? Which one is right?
  • Dejell
    Dejell about 9 years
    @BalusC was it fixed in tomcat 8?