or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

api-versioning.mdasync.mdconfiguration.mdcontent-negotiation.mdcontroller-annotations.mdcore-framework.mdcors.mddata-binding.mdexception-handling.mdflash-attributes.mdfunctional-endpoints.mdi18n.mdindex.mdinterceptors.mdmultipart.mdrequest-binding.mdresource-handling.mdresponse-handling.mduri-building.mdview-resolution.md
tile.json

interceptors.mddocs/

Interceptors

Handler interceptors for pre-processing and post-processing of requests, enabling cross-cutting concerns like logging, authentication, localization, and performance monitoring.

Capabilities

HandlerInterceptor

Interface for intercepting handler method execution with callbacks before, after, and upon completion of request processing.

/**
 * Workflow interface that allows for customized handler execution chains.
 * Applications can register any number of existing or custom interceptors
 * for certain groups of handlers, to add common preprocessing behavior
 * without needing to modify each handler implementation.
 */
public interface HandlerInterceptor {
    /**
     * Intercept the execution of a handler. Called after HandlerMapping determined
     * an appropriate handler object, but before HandlerAdapter invokes the handler.
     *
     * @param request current HTTP request
     * @param response current HTTP response
     * @param handler chosen handler to execute, for type and/or instance evaluation
     * @return true if the execution chain should proceed with the next interceptor
     * or the handler itself. Else, DispatcherServlet assumes that this interceptor
     * has already dealt with the response itself
     * @throws Exception in case of errors
     */
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        return true;
    }

    /**
     * Intercept the execution of a handler. Called after HandlerAdapter actually
     * invoked the handler, but before the DispatcherServlet renders the view.
     * Can expose additional model objects to the view via the given ModelAndView.
     *
     * @param request current HTTP request
     * @param response current HTTP response
     * @param handler the handler (or HandlerMethod) that started asynchronous execution
     * @param modelAndView the ModelAndView that the handler returned
     * @throws Exception in case of errors
     */
    default void postHandle(HttpServletRequest request, HttpServletResponse response,
                          Object handler, ModelAndView modelAndView) throws Exception {
    }

    /**
     * Callback after completion of request processing, that is, after rendering
     * the view. Will be called on any outcome of handler execution, thus allows
     * for proper resource cleanup.
     *
     * @param request current HTTP request
     * @param response current HTTP response
     * @param handler the handler (or HandlerMethod) that started asynchronous execution
     * @param ex any exception thrown on handler execution, if any
     * @throws Exception in case of errors
     */
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
    }
}

Usage Example:

public class LoggingInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                            Object handler) throws Exception {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);

        logger.info("Request URL: {} - Method: {} - Started at: {}",
            request.getRequestURI(), request.getMethod(), startTime);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                         Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("Request processed, view: {}",
            modelAndView != null ? modelAndView.getViewName() : "null");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                              Object handler, Exception ex) throws Exception {
        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;

        logger.info("Request URL: {} - Completed in: {} ms",
            request.getRequestURI(), duration);

        if (ex != null) {
            logger.error("Request failed with exception", ex);
        }
    }
}

// Authentication interceptor
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                            Object handler) throws Exception {
        String authToken = request.getHeader("Authorization");

        if (authToken == null || !authService.validateToken(authToken)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Unauthorized");
            return false;
        }

        User user = authService.getUserFromToken(authToken);
        request.setAttribute("authenticatedUser", user);
        return true;
    }
}

// Configuration
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor())
            .addPathPatterns("/**");

        registry.addInterceptor(new AuthenticationInterceptor())
            .addPathPatterns("/api/**")
            .excludePathPatterns("/api/public/**")
            .order(1);
    }
}

AsyncHandlerInterceptor

Extension of HandlerInterceptor with a callback method for asynchronous request processing.

/**
 * Extends HandlerInterceptor with a callback method invoked during asynchronous
 * request handling.
 *
 * When a handler starts asynchronous request processing, the DispatcherServlet
 * exits without invoking postHandle and afterCompletion, as it normally does,
 * since the results of request handling (e.g. ModelAndView) are not available
 * in the current thread and handling is not yet complete.
 */
public interface AsyncHandlerInterceptor extends HandlerInterceptor {
    /**
     * Called instead of postHandle and afterCompletion when the handler is being
     * executed concurrently.
     *
     * Implementations of this method should use the provided request and response
     * but avoid modifying them in ways that would conflict with the concurrent
     * execution of the handler.
     *
     * @param request the current request
     * @param response the current response
     * @param handler the handler (or HandlerMethod) that started asynchronous execution
     * @throws Exception in case of errors
     */
    default void afterConcurrentHandlingStarted(HttpServletRequest request,
                                               HttpServletResponse response,
                                               Object handler) throws Exception {
    }
}

MappedInterceptor

Contains and delegates calls to a HandlerInterceptor along with include and exclude path patterns.

/**
 * Contains and delegates calls to a HandlerInterceptor along with include (and optionally
 * exclude) path patterns to which the interceptor should apply.
 */
public final class MappedInterceptor implements HandlerInterceptor {
    /**
     * Create a new MappedInterceptor instance.
     *
     * @param includePatterns the path patterns to map with a null match to all paths
     * @param interceptor the HandlerInterceptor to delegate to
     */
    public MappedInterceptor(String[] includePatterns, HandlerInterceptor interceptor) {}

    /**
     * Create a new MappedInterceptor instance.
     *
     * @param includePatterns the path patterns to map
     * @param excludePatterns the path patterns to exclude
     * @param interceptor the HandlerInterceptor to delegate to
     */
    public MappedInterceptor(String[] includePatterns, String[] excludePatterns,
                            HandlerInterceptor interceptor) {}

    /**
     * Return the path into the application for which this interceptor should apply.
     * Supports direct matches, e.g. "/admin" and pattern matches, e.g. "/admin/**".
     *
     * @return the include patterns, or null
     */
    public String[] getIncludePatterns() {}

    /**
     * Return the path patterns for which this interceptor should not apply.
     *
     * @return the exclude patterns, or null
     */
    public String[] getExcludePatterns() {}

    /**
     * Return the actual interceptor.
     *
     * @return the interceptor
     */
    public HandlerInterceptor getInterceptor() {}

    /**
     * Check whether this interceptor is mapped to the given request path.
     *
     * @param lookupPath the current request path
     * @param pathMatcher the path matcher to use for pattern matching
     * @return true if the interceptor applies to the given path
     */
    public boolean matches(String lookupPath, PathMatcher pathMatcher) {}
}

Usage Example:

@Bean
public MappedInterceptor adminInterceptor() {
    return new MappedInterceptor(
        new String[]{"/admin/**"},
        new String[]{"/admin/login"},
        new AdminAuthenticationInterceptor()
    );
}

Types

InterceptorRegistry

Registry for configuring interceptors.

public class InterceptorRegistry {
    public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {}
}

InterceptorRegistration

Configuration for a single interceptor.

public class InterceptorRegistration {
    public InterceptorRegistration addPathPatterns(String... patterns) {}
    public InterceptorRegistration excludePathPatterns(String... patterns) {}
    public InterceptorRegistration pathMatcher(PathMatcher pathMatcher) {}
    public InterceptorRegistration order(int order) {}
}