9

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.

Community
  • 1
  • 1
AndrewBourgeois
  • 2,634
  • 7
  • 41
  • 58

2 Answers2

13

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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I'm OK with using 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 ...? – AndrewBourgeois Jun 03 '12 at 19:45
  • 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 Jun 03 '12 at 20:53
  • 2
    FYI: has been [fixed](https://issues.apache.org/bugzilla/show_bug.cgi?id=53354#c1) by [Mark](http://stackoverflow.com/users/1299005/mark-thomas) some secs ago. Will be in 7.0.28 and onwards. – BalusC Jun 03 '12 at 21:19
  • 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? – AndrewBourgeois Oct 15 '12 at 23:47
  • 1
    @BalusC was it fixed in tomcat 8? – Dejell Feb 18 '15 at 13:03
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
Jens
  • 67,715
  • 15
  • 98
  • 113
Pidster
  • 628
  • 4
  • 9
  • I'm only removing the elements from my web.xml, not the elements. As answered in the following question, it should work: http://stackoverflow.com/questions/6560969/how-to-define-servlet-filter-order-of-execution-using-annotations. It only works when I deploy it in a Glassfish environment. – AndrewBourgeois Jun 03 '12 at 18:18