24

I'd like to have ETag suport. For this purpose there is a ShallowEtagHeaderFilter which does all the work. How can I add it without declaring it in my web.xml (which actually does not exist, because I somehow got by without it so far)?

P.S. I use Spring Boot 1.1.4

P.P.S. Here's a full solution

package cuenation.api;

import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.ShallowEtagHeaderFilter;

import javax.servlet.DispatcherType;
import java.util.EnumSet;

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean shallowEtagHeaderFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new ShallowEtagHeaderFilter());
        registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
        registration.addUrlPatterns("/cue-categories");
        return registration;
    }

}
dVaffection
  • 1,434
  • 2
  • 14
  • 23
  • Uhm, your question contains a link to the solution. Just scroll down a few lines. – a better oliver Oct 02 '14 at 07:47
  • @zeroflagL Scroll down a few lines where: here or in the spring documentation? I'm not following you! – dVaffection Oct 02 '14 at 17:44
  • @zeroflagL Oh, I see what you mean. But my problem is I don't have any xml configuration whatsoever. See [my custom initializer](https://gist.github.com/dVaffection/259156e18b2ac5660dc2). What am I doing wrong? – dVaffection Oct 02 '14 at 18:33
  • duplicate question... http://stackoverflow.com/questions/19825946/how-to-add-a-filter-class-in-spring-boot – Brian Clozel Oct 02 '14 at 19:13
  • how to add ShallowEtagHeaderFilter to the project so that it can evaluate and send Etag to the browser. Do we need to override anything? – Tushar Jul 13 '16 at 22:05

2 Answers2

35

When using Spring Boot

As mentioned in the reference documentation, the only step needed is to declare that filter as a Bean in a configuration class, that's it!

@Configuration
public class WebConfig {

  @Bean
  public Filter shallowEtagHeaderFilter() {
    return new ShallowEtagHeaderFilter();
  }
}

When using Spring MVC

You're probably already extending a WebApplicationInitializer. If not, then you should convert your webapp configuration from a web.xml file to a WebApplicationInitializer class.

If your context configuration lives in XML file(s), you can create a class that extends AbstractDispatcherServletInitializer - if using configuration classes, AbstractAnnotationConfigDispatcherServletInitializer is the proper choice.

In any case, you can then add Filter registration:

  @Override
  protected Filter[] getServletFilters() {
    return new Filter[] {
      new ShallowEtagHeaderFilter();
    };
  }

Full examples of code-based Servlet container initialization are available in the Spring reference documentation.

Brian Clozel
  • 46,620
  • 12
  • 129
  • 152
  • No I don't extend `WebApplicationInitializer` neither directly nor indirectly. Actually the only config I have is `application.properties` where I put my mongodb connection string. I tried to extend `AbstractAnnotationConfigDispatcherServletInitializer` but it requires to implement me a bunch of methods. – dVaffection Oct 02 '14 at 17:43
  • Ok, I added [my custom initializer](https://gist.github.com/dVaffection/259156e18b2ac5660dc2). But looks like spring does not see it. What did I mess here? – dVaffection Oct 02 '14 at 18:12
  • so you probably have a web.xml file somewhere... it's either web.xml (configuring your webapp with XML) or a WebApplicationInitializer. I'm adding a complete example in my answer. – Brian Clozel Oct 02 '14 at 18:55
  • No, as I said above I don't have any configuration files other than `application.properties` – dVaffection Oct 02 '14 at 19:02
  • Are you using Spring Boot then? – Brian Clozel Oct 02 '14 at 19:04
  • Yes, I use spring-boot-starter-web 1.1.4 – dVaffection Oct 02 '14 at 19:06
  • I've seen this [17.15 Code-based Servlet container initialization](http://docs.spring.io/spring/docs/4.1.1.RELEASE/spring-framework-reference/html/mvc.html#mvc-container-config). My frustration comes because they use `dispatcher-config.xml`. I don't know what it is! – dVaffection Oct 02 '14 at 19:08
  • updated my answer - you should have made clear from the start that you're using Spring Boot... – Brian Clozel Oct 02 '14 at 19:12
  • Hm, I added `WebConfig` class inside my [Application](https://gist.github.com/dVaffection/9c75855adec931be999b) but TomCat does not start saying `Could not instantiate bean class [cuenation.api.Application$WebConfig$$EnhancerBySpringCGLIB$$6aed0802]: No default constructor found;` – dVaffection Oct 02 '14 at 19:28
  • 2
    Ok, I finally [figured this out](https://gist.github.com/dVaffection/24b127a6cbeae49fb48b) – dVaffection Oct 02 '14 at 21:00
  • Trying your approach spawned a new and different error, which warrants a new posting. Inserting your code is giving a `No default constructor` error. Are you willing to comment? Here is the link: http://stackoverflow.com/questions/36533585/no-default-constructor-when-adding-servlet-filter-in-spring-boot – CodeMed Apr 10 '16 at 18:14
  • Is it same as if we register filters using configure(HttpSecurity http) by addFilterBefore and addFilterAfter methods – Harshana Aug 11 '16 at 04:30
3

A bit late answer.

My solution was to create custom annotation:

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

// ...

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface Filter {

    @AliasFor(annotation = Component.class, attribute = "value")
    String value() default "";

}

And then simply apply it to the filter implementations:

@Filter
public class CustomFilter extends AbstractRequestLoggingFilter {

    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        logger.debug("before req params:", request.getParameterMap());
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        logger.debug("after req params:", request.getParameterMap());
    }
}

See more: @AliasFor, Spring custom annotations question

Community
  • 1
  • 1
Andrii Abramov
  • 7,967
  • 8
  • 55
  • 79