or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

adapter-support.mdclient-support.mdconfiguration.mdcore-websocket.mdhandlers.mdindex.mdserver-support.mdsockjs-client.mdsockjs-frames.mdsockjs-support.mdstomp-messaging.md
tile.json

server-support.mddocs/

Server Support

Server-side WebSocket handshake processing, protocol upgrade strategies, and integration with WebSocket server implementations. Handles HTTP to WebSocket protocol upgrades and provides adapters for standard JSR-356 and Jetty servers.

Capabilities

HandshakeHandler Interface

Processes the WebSocket handshake request and performs the protocol upgrade.

/**
 * Contract for processing a WebSocket handshake request. Implementations
 * handle the HTTP upgrade protocol to establish a WebSocket connection.
 */
public interface HandshakeHandler {
    /**
     * Initiate the handshake by processing the request and upgrading to
     * the WebSocket protocol.
     *
     * @param request    the HTTP request
     * @param response   the HTTP response
     * @param wsHandler  the WebSocket handler for the connection
     * @param attributes attributes from HandshakeInterceptors
     * @return true if the handshake succeeds, false otherwise
     * @throws HandshakeFailureException if the handshake fails
     */
    boolean doHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws HandshakeFailureException;
}

HandshakeInterceptor Interface

Intercepts WebSocket handshake requests before and after the handshake is processed.

/**
 * Allows interception of WebSocket handshake requests. Interceptors can
 * inspect the request, modify attributes, or prevent the handshake from
 * proceeding.
 */
public interface HandshakeInterceptor {
    /**
     * Invoked before the handshake is processed. Return false to prevent
     * the handshake from proceeding.
     *
     * @param request    the HTTP request
     * @param response   the HTTP response
     * @param wsHandler  the target WebSocket handler
     * @param attributes attributes to pass to the WebSocket session
     * @return true to proceed with the handshake, false to abort
     * @throws Exception if an error occurs
     */
    boolean beforeHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception;

    /**
     * Invoked after the handshake is processed, regardless of outcome.
     *
     * @param request    the HTTP request
     * @param response   the HTTP response
     * @param wsHandler  the target WebSocket handler
     * @param exception  the exception if handshake failed, null otherwise
     */
    void afterHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Exception exception);
}

RequestUpgradeStrategy Interface

Server-specific strategy for upgrading HTTP requests to WebSocket connections.

/**
 * A server-specific strategy for performing the actual HTTP to WebSocket
 * protocol upgrade. Different WebSocket server implementations require
 * different upgrade mechanisms.
 */
public interface RequestUpgradeStrategy {
    /**
     * Return the WebSocket protocol versions supported by this strategy.
     *
     * @return an array of supported version strings (e.g., "13")
     */
    String[] getSupportedVersions();

    /**
     * Return the WebSocket extensions supported by the server for the
     * given request.
     *
     * @param request the HTTP request
     * @return list of supported extensions
     */
    List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request);

    /**
     * Perform the actual upgrade from HTTP to WebSocket protocol.
     *
     * @param request            the HTTP request
     * @param response           the HTTP response
     * @param selectedProtocol   the selected sub-protocol, may be null
     * @param selectedExtensions the selected extensions
     * @param user               the user principal, may be null
     * @param wsHandler          the WebSocket handler
     * @param attributes         attributes from interceptors
     * @throws HandshakeFailureException if upgrade fails
     */
    void upgrade(
            ServerHttpRequest request,
            ServerHttpResponse response,
            String selectedProtocol,
            List<WebSocketExtension> selectedExtensions,
            Principal user,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws HandshakeFailureException;
}

AbstractHandshakeHandler

Base implementation of HandshakeHandler with common handshake logic.

/**
 * Abstract base class for HandshakeHandler implementations. Provides
 * common handshake processing logic including sub-protocol negotiation,
 * extension negotiation, and user principal determination.
 */
public abstract class AbstractHandshakeHandler implements HandshakeHandler {
    /**
     * Create a new handshake handler with default RequestUpgradeStrategy.
     * The strategy is auto-detected based on the runtime environment.
     */
    public AbstractHandshakeHandler();

    /**
     * Create a new handshake handler with the given upgrade strategy.
     *
     * @param upgradeStrategy the upgrade strategy to use
     */
    public AbstractHandshakeHandler(RequestUpgradeStrategy upgradeStrategy);

    /**
     * Determine the user principal to associate with the WebSocket session.
     * Default implementation returns the principal from the HTTP request.
     *
     * @param request    the HTTP request
     * @param wsHandler  the WebSocket handler
     * @param attributes handshake attributes
     * @return the user principal, or null if none
     */
    protected Principal determineUser(
            ServerHttpRequest request,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes);

    @Override
    public boolean doHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws HandshakeFailureException;
}

DefaultHandshakeHandler

Default HandshakeHandler implementation supporting standard WebSocket servers.

/**
 * Default HandshakeHandler implementation. Auto-detects the WebSocket
 * server runtime and uses the appropriate RequestUpgradeStrategy.
 * Supports JSR-356 (Jakarta WebSocket), Jetty, and other standard
 * WebSocket server implementations.
 */
public class DefaultHandshakeHandler extends AbstractHandshakeHandler {
    /**
     * Create a handler with auto-detected RequestUpgradeStrategy.
     * Detects Jetty, Tomcat, Undertow, or uses standard JSR-356.
     */
    public DefaultHandshakeHandler();

    /**
     * Create a handler with a specific RequestUpgradeStrategy.
     *
     * @param upgradeStrategy the upgrade strategy to use
     */
    public DefaultHandshakeHandler(RequestUpgradeStrategy upgradeStrategy);

    /**
     * Set the supported sub-protocols. Used during sub-protocol negotiation.
     *
     * @param protocols the supported sub-protocols
     */
    public void setSupportedProtocols(String... protocols);

    /**
     * Get the list of supported sub-protocols.
     *
     * @return the supported sub-protocols
     */
    public String[] getSupportedProtocols();
}

HttpSessionHandshakeInterceptor

Copies HTTP session attributes to the WebSocket session.

/**
 * HandshakeInterceptor that copies HTTP session attributes into the
 * WebSocket session attributes map. Useful for passing HTTP session
 * data to the WebSocket handler.
 */
public class HttpSessionHandshakeInterceptor implements HandshakeInterceptor {
    /**
     * Attribute name for the HTTP session ID in WebSocket attributes.
     * Value: "HTTP.SESSION.ID"
     */
    public static final String HTTP_SESSION_ID_ATTR_NAME = "HTTP.SESSION.ID";

    /**
     * Create an interceptor that copies all HTTP session attributes.
     */
    public HttpSessionHandshakeInterceptor();

    /**
     * Create an interceptor with configuration for which attributes to copy.
     *
     * @param copyAllAttributes   whether to copy all HTTP session attributes
     */
    public HttpSessionHandshakeInterceptor(boolean copyAllAttributes);

    /**
     * Set the names of specific HTTP session attributes to copy.
     * If not set and copyAllAttributes is true, all attributes are copied.
     *
     * @param attributeNames the attribute names to copy
     */
    public void setAttributeNames(Collection<String> attributeNames);

    /**
     * Get the configured attribute names to copy.
     *
     * @return the attribute names, or null if all attributes are copied
     */
    public Collection<String> getAttributeNames();

    /**
     * Whether to create an HTTP session if one doesn't exist.
     * Default is true.
     *
     * @param createSession whether to create HTTP session
     */
    public void setCreateSession(boolean createSession);

    /**
     * Whether to create an HTTP session if one doesn't exist.
     *
     * @return true if session creation is enabled
     */
    public boolean isCreateSession();

    @Override
    public boolean beforeHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception;

    @Override
    public void afterHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Exception exception);
}

OriginHandshakeInterceptor

Validates the Origin header to implement cross-origin request security.

/**
 * HandshakeInterceptor that checks the Origin header against allowed
 * origins to implement same-origin policy or CORS security.
 */
public class OriginHandshakeInterceptor implements HandshakeInterceptor {
    /**
     * Create an interceptor that rejects all cross-origin requests.
     */
    public OriginHandshakeInterceptor();

    /**
     * Create an interceptor with allowed origins.
     *
     * @param allowedOrigins the allowed origin values (e.g., "https://example.com")
     */
    public OriginHandshakeInterceptor(Collection<String> allowedOrigins);

    /**
     * Set allowed origin values. An origin is allowed if it matches one
     * of these values. Use "*" to allow all origins.
     *
     * @param allowedOrigins the allowed origins
     */
    public void setAllowedOrigins(Collection<String> allowedOrigins);

    /**
     * Set allowed origin patterns with wildcard support.
     * Example: "https://*.example.com"
     *
     * @param allowedOriginPatterns the allowed origin patterns
     */
    public void setAllowedOriginPatterns(Collection<String> allowedOriginPatterns);

    @Override
    public boolean beforeHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception;

    @Override
    public void afterHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Exception exception);
}

WebSocketHttpRequestHandler

HTTP request handler that processes WebSocket handshake requests.

/**
 * HttpRequestHandler that processes WebSocket handshake requests.
 * Delegates to HandshakeHandler and applies HandshakeInterceptors.
 */
public class WebSocketHttpRequestHandler implements HttpRequestHandler {
    /**
     * Create a request handler for the given WebSocket handler.
     *
     * @param wsHandler the WebSocket handler
     */
    public WebSocketHttpRequestHandler(WebSocketHandler wsHandler);

    /**
     * Create a request handler with a custom handshake handler.
     *
     * @param wsHandler        the WebSocket handler
     * @param handshakeHandler the handshake handler
     */
    public WebSocketHttpRequestHandler(
            WebSocketHandler wsHandler,
            HandshakeHandler handshakeHandler);

    /**
     * Set the HandshakeHandler to use for processing handshakes.
     *
     * @param handshakeHandler the handshake handler
     */
    public void setHandshakeHandler(HandshakeHandler handshakeHandler);

    /**
     * Get the configured HandshakeHandler.
     *
     * @return the handshake handler
     */
    public HandshakeHandler getHandshakeHandler();

    /**
     * Set HandshakeInterceptors to apply to handshake requests.
     *
     * @param interceptors the interceptors to apply
     */
    public void setHandshakeInterceptors(List<HandshakeInterceptor> interceptors);

    /**
     * Get the configured HandshakeInterceptors.
     *
     * @return the interceptors
     */
    public List<HandshakeInterceptor> getHandshakeInterceptors();

    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException;
}

StandardWebSocketUpgradeStrategy

JSR-356 (Jakarta WebSocket) implementation of RequestUpgradeStrategy.

/**
 * RequestUpgradeStrategy for standard JSR-356 runtimes (Jakarta WebSocket).
 * Works with any servlet container that supports JSR-356 including Tomcat,
 * Jetty, Undertow, and WildFly.
 */
public class StandardWebSocketUpgradeStrategy implements RequestUpgradeStrategy {
    /**
     * Create an upgrade strategy using the default WebSocketContainer.
     */
    public StandardWebSocketUpgradeStrategy();

    /**
     * Create an upgrade strategy using a specific WebSocketContainer.
     *
     * @param webSocketContainer the WebSocket container to use
     */
    public StandardWebSocketUpgradeStrategy(WebSocketContainer webSocketContainer);

    /**
     * Set extensions to enable. By default, all supported extensions are enabled.
     *
     * @param extensions the extensions to enable
     */
    public void setExtensions(List<Extension> extensions);

    /**
     * Get the configured extensions.
     *
     * @return the extensions
     */
    public List<Extension> getExtensions();

    @Override
    public String[] getSupportedVersions();

    @Override
    public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request);

    @Override
    public void upgrade(
            ServerHttpRequest request,
            ServerHttpResponse response,
            String selectedProtocol,
            List<WebSocketExtension> selectedExtensions,
            Principal user,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws HandshakeFailureException;
}

JettyRequestUpgradeStrategy

Jetty-specific implementation of RequestUpgradeStrategy.

/**
 * RequestUpgradeStrategy for Jetty WebSocket server.
 * Provides native Jetty WebSocket support with better performance
 * than the standard JSR-356 approach.
 */
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
    /**
     * Create a Jetty upgrade strategy with default configuration.
     */
    public JettyRequestUpgradeStrategy();

    /**
     * Create a Jetty upgrade strategy with a specific WebSocketPolicy.
     *
     * @param policy the WebSocket policy for configuration
     */
    public JettyRequestUpgradeStrategy(WebSocketPolicy policy);

    /**
     * Set the WebSocketPolicy for configuring buffer sizes, timeouts, etc.
     *
     * @param policy the policy to use
     */
    public void setPolicy(WebSocketPolicy policy);

    /**
     * Get the configured WebSocketPolicy.
     *
     * @return the policy
     */
    public WebSocketPolicy getPolicy();

    @Override
    public String[] getSupportedVersions();

    @Override
    public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request);

    @Override
    public void upgrade(
            ServerHttpRequest request,
            ServerHttpResponse response,
            String selectedProtocol,
            List<WebSocketExtension> selectedExtensions,
            Principal user,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws HandshakeFailureException;
}

WebSocketHandlerMapping

Extension of SimpleUrlHandlerMapping with WebSocket-specific handler mapping.

/**
 * Extension of SimpleUrlHandlerMapping with support for more precise
 * mapping of WebSocket handshake requests to handlers of type
 * WebSocketHttpRequestHandler. Also delegates Lifecycle methods to
 * handlers that implement it.
 *
 * @since 4.2
 */
public class WebSocketHandlerMapping extends SimpleUrlHandlerMapping
        implements SmartLifecycle {
    /**
     * When enabled, if the matched handler is WebSocketHttpRequestHandler,
     * ensures the request is a WebSocket handshake (HTTP GET with
     * "Upgrade:websocket" header), or suppresses the match returning null
     * to allow another HandlerMapping to match.
     *
     * @param match whether to enable matching on "Upgrade: websocket"
     * @since 5.3.5
     */
    public void setWebSocketUpgradeMatch(boolean match);

    /**
     * Set the phase that this handler should run in.
     * By default, this is SmartLifecycle.DEFAULT_PHASE, but with
     * @EnableWebSocketMessageBroker configuration it is set to 0.
     *
     * @param phase the lifecycle phase
     * @since 6.1.4
     */
    public void setPhase(int phase);

    @Override
    public int getPhase();

    @Override
    public void start();

    @Override
    public void stop();

    @Override
    public boolean isRunning();

    @Override
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception;
}

Jakarta WebSocket (JSR-356) Support

Spring provides comprehensive support for Jakarta WebSocket (JSR-356) endpoints, enabling dependency injection and Spring-based configuration for standard WebSocket endpoints.

ServerEndpointExporter

Detects and registers @ServerEndpoint annotated beans with the WebSocket runtime.

/**
 * Detects beans of type ServerEndpointConfig and registers with the
 * standard Jakarta WebSocket runtime. Also detects beans annotated with
 * @ServerEndpoint and registers them as well. Although not required, it
 * is likely annotated endpoints should have their configurator property
 * set to SpringConfigurator.
 *
 * When this class is used, by declaring it in Spring configuration, it
 * should be possible to turn off a Servlet container's scan for WebSocket
 * endpoints. This can be done with the help of the <absolute-ordering>
 * element in web.xml.
 *
 * @since 4.0
 * @see ServerEndpointRegistration
 * @see SpringConfigurator
 * @see ServletServerContainerFactoryBean
 */
public class ServerEndpointExporter extends WebApplicationObjectSupport
        implements InitializingBean, SmartInitializingSingleton {
    /**
     * Explicitly list annotated endpoint types that should be registered
     * on startup. This can be done if you wish to turn off a Servlet
     * container's scan for endpoints, which goes through all 3rd party
     * jars in the classpath, and rely on Spring configuration instead.
     *
     * @param annotatedEndpointClasses @ServerEndpoint-annotated types
     */
    public void setAnnotatedEndpointClasses(Class<?>... annotatedEndpointClasses);

    /**
     * Set the JSR-356 ServerContainer to use for endpoint registration.
     * If not set, the container is going to be retrieved via the ServletContext.
     *
     * @param serverContainer the ServerContainer to use
     */
    public void setServerContainer(ServerContainer serverContainer);

    /**
     * Return the JSR-356 ServerContainer to use for endpoint registration.
     *
     * @return the ServerContainer
     */
    protected ServerContainer getServerContainer();

    @Override
    public void afterPropertiesSet();

    @Override
    public void afterSingletonsInstantiated();

    /**
     * Actually register the endpoints. Called by afterSingletonsInstantiated().
     */
    protected void registerEndpoints();
}

ServletServerContainerFactoryBean

FactoryBean for configuring the JSR-356 ServerContainer.

/**
 * A FactoryBean for configuring ServerContainer. Since there is usually
 * only one ServerContainer instance accessible under a well-known
 * ServletContext attribute, simply declaring this FactoryBean and using
 * its setters allows for configuring the ServerContainer through Spring
 * configuration.
 *
 * This is useful even if the ServerContainer is not injected into any
 * other bean within the Spring application context. For example, an
 * application can configure a DefaultHandshakeHandler, a SockJsService,
 * or ServerEndpointExporter, and separately declare this FactoryBean in
 * order to customize the properties of the (one and only) ServerContainer
 * instance.
 *
 * @since 4.0
 */
public class ServletServerContainerFactoryBean
        implements FactoryBean<WebSocketContainer>, ServletContextAware, InitializingBean {
    /**
     * Set the timeout for async sending operations in milliseconds.
     *
     * @param timeoutInMillis the async send timeout
     */
    public void setAsyncSendTimeout(Long timeoutInMillis);

    /**
     * Get the configured async send timeout.
     *
     * @return the timeout in milliseconds
     */
    public Long getAsyncSendTimeout();

    /**
     * Set the maximum idle timeout for WebSocket sessions in milliseconds.
     *
     * @param timeoutInMillis the max session idle timeout
     */
    public void setMaxSessionIdleTimeout(Long timeoutInMillis);

    /**
     * Get the configured max session idle timeout.
     *
     * @return the timeout in milliseconds
     */
    public Long getMaxSessionIdleTimeout();

    /**
     * Set the maximum size of text message buffers.
     *
     * @param bufferSize the buffer size in bytes
     */
    public void setMaxTextMessageBufferSize(Integer bufferSize);

    /**
     * Get the configured max text message buffer size.
     *
     * @return the buffer size in bytes
     */
    public Integer getMaxTextMessageBufferSize();

    /**
     * Set the maximum size of binary message buffers.
     *
     * @param bufferSize the buffer size in bytes
     */
    public void setMaxBinaryMessageBufferSize(Integer bufferSize);

    /**
     * Get the configured max binary message buffer size.
     *
     * @return the buffer size in bytes
     */
    public Integer getMaxBinaryMessageBufferSize();

    @Override
    public void setServletContext(ServletContext servletContext);

    @Override
    public void afterPropertiesSet();

    @Override
    public ServerContainer getObject();

    @Override
    public Class<?> getObjectType();

    @Override
    public boolean isSingleton();
}

SpringConfigurator

JSR-356 Configurator that enables Spring dependency injection in @ServerEndpoint annotated classes.

/**
 * A ServerEndpointConfig.Configurator for initializing @ServerEndpoint
 * annotated classes through Spring.
 *
 * Example usage:
 * <pre class="code">
 * &#064;ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class)
 * public class EchoEndpoint {
 *     // ...
 * }
 * </pre>
 *
 * @since 4.0
 * @see ServerEndpointExporter
 */
public class SpringConfigurator extends ServerEndpointConfig.Configurator {
    /**
     * Get an endpoint instance from the Spring ApplicationContext. First
     * attempts to find the endpoint as a Spring bean by short name, then
     * by @Component value, then by type. If no bean is found, creates a
     * new instance using Spring's AutowireCapableBeanFactory to enable
     * dependency injection.
     *
     * @param endpointClass the endpoint class
     * @return the endpoint instance
     * @throws InstantiationException if the endpoint cannot be instantiated
     */
    @Override
    public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException;
}

ServerEndpointRegistration

Programmatic registration for JSR-356 ServerEndpoint without using annotations.

/**
 * An implementation of ServerEndpointConfig for use in Spring-based
 * applications. A ServerEndpointRegistration bean is detected by
 * ServerEndpointExporter and registered with a Jakarta WebSocket runtime
 * at startup.
 *
 * Class constructors accept a singleton Endpoint instance or an Endpoint
 * specified by type Class. When specified by type, the endpoint will be
 * instantiated and initialized through the Spring ApplicationContext
 * before each client WebSocket connection.
 *
 * This class also extends ServerEndpointConfig.Configurator to make it
 * easier to override methods for customizing the handshake process.
 *
 * @since 4.0
 * @see ServerEndpointExporter
 */
public class ServerEndpointRegistration extends ServerEndpointConfig.Configurator
        implements ServerEndpointConfig, BeanFactoryAware {
    /**
     * Create a new ServerEndpointRegistration instance from an
     * Endpoint instance.
     *
     * @param path     the endpoint path
     * @param endpoint the endpoint instance
     */
    public ServerEndpointRegistration(String path, Endpoint endpoint);

    /**
     * Create a new ServerEndpointRegistration instance from an
     * Endpoint class.
     *
     * @param path          the endpoint path
     * @param endpointClass the endpoint class
     */
    public ServerEndpointRegistration(String path, Class<? extends Endpoint> endpointClass);

    @Override
    public String getPath();

    @Override
    public Class<? extends Endpoint> getEndpointClass();

    /**
     * Get the endpoint instance. If a class was specified in the
     * constructor, this creates a new instance using Spring.
     *
     * @return the endpoint instance
     */
    public Endpoint getEndpoint();

    /**
     * Set the sub-protocols this endpoint supports.
     *
     * @param subprotocols the supported sub-protocols
     */
    public void setSubprotocols(List<String> subprotocols);

    @Override
    public List<String> getSubprotocols();

    /**
     * Set the extensions this endpoint supports.
     *
     * @param extensions the supported extensions
     */
    public void setExtensions(List<Extension> extensions);

    @Override
    public List<Extension> getExtensions();

    /**
     * Set encoders for this endpoint.
     *
     * @param encoders the encoder classes
     */
    public void setEncoders(List<Class<? extends Encoder>> encoders);

    @Override
    public List<Class<? extends Encoder>> getEncoders();

    /**
     * Set decoders for this endpoint.
     *
     * @param decoders the decoder classes
     */
    public void setDecoders(List<Class<? extends Decoder>> decoders);

    @Override
    public List<Class<? extends Decoder>> getDecoders();

    /**
     * Set user properties for this endpoint.
     *
     * @param userProperties the user properties map
     */
    public void setUserProperties(Map<String, Object> userProperties);

    @Override
    public Map<String, Object> getUserProperties();

    @Override
    public Configurator getConfigurator();

    @Override
    public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException;

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request,
            HandshakeResponse response);

    @Override
    public void setBeanFactory(BeanFactory beanFactory);
}

HandshakeFailureException

Exception thrown when a WebSocket handshake fails.

/**
 * Exception thrown to indicate a WebSocket handshake failure.
 */
public class HandshakeFailureException extends Exception {
    /**
     * Create an exception with a message.
     *
     * @param message the error message
     */
    public HandshakeFailureException(String message);

    /**
     * Create an exception with a message and cause.
     *
     * @param message the error message
     * @param cause   the underlying cause
     */
    public HandshakeFailureException(String message, Throwable cause);
}

Usage Examples

Basic Handshake Handler Configuration

import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "/ws")
                .setHandshakeHandler(handshakeHandler())
                .addInterceptors(new HttpSessionHandshakeInterceptor());
    }

    @Bean
    public HandshakeHandler handshakeHandler() {
        return new DefaultHandshakeHandler();
    }

    @Bean
    public WebSocketHandler myHandler() {
        return new MyWebSocketHandler();
    }
}

Custom User Principal Determination

import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
import org.springframework.http.server.ServerHttpRequest;

@Bean
public HandshakeHandler customHandshakeHandler() {
    return new DefaultHandshakeHandler() {
        @Override
        protected Principal determineUser(
                ServerHttpRequest request,
                WebSocketHandler wsHandler,
                Map<String, Object> attributes) {

            // Extract user from custom header
            HttpHeaders headers = request.getHeaders();
            String username = headers.getFirst("X-User-Name");

            if (username != null) {
                return new SimplePrincipal(username);
            }

            // Fall back to authenticated principal
            return request.getPrincipal();
        }
    };
}

// Simple Principal implementation
class SimplePrincipal implements Principal {
    private final String name;

    public SimplePrincipal(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }
}

Custom Handshake Interceptor

import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;

public class AuthenticationHandshakeInterceptor implements HandshakeInterceptor {

    @Override
    public boolean beforeHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {

        // Extract authentication token
        String token = extractToken(request);

        if (token == null || !isValidToken(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return false;  // Reject handshake
        }

        // Store authenticated user in attributes
        User user = getUserFromToken(token);
        attributes.put("user", user);

        return true;  // Proceed with handshake
    }

    @Override
    public void afterHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Exception exception) {

        if (exception != null) {
            // Log handshake failure
            System.err.println("Handshake failed: " + exception.getMessage());
        }
    }

    private String extractToken(ServerHttpRequest request) {
        // Extract from query parameter or header
        URI uri = request.getURI();
        String query = uri.getQuery();

        if (query != null && query.contains("token=")) {
            return query.split("token=")[1].split("&")[0];
        }

        return request.getHeaders().getFirst("Authorization");
    }

    private boolean isValidToken(String token) {
        // Validate token
        return token != null && token.length() > 0;
    }

    private User getUserFromToken(String token) {
        // Decode and return user
        return new User(token);
    }
}

CORS Configuration with Origin Interceptor

import org.springframework.web.socket.server.support.OriginHandshakeInterceptor;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        OriginHandshakeInterceptor originInterceptor = new OriginHandshakeInterceptor(
                Arrays.asList(
                    "https://example.com",
                    "https://app.example.com"
                )
        );

        registry.addHandler(myHandler(), "/ws")
                .addInterceptors(originInterceptor);
    }
}

HTTP Session Attributes Transfer

import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // Copy specific HTTP session attributes
        HttpSessionHandshakeInterceptor sessionInterceptor =
                new HttpSessionHandshakeInterceptor();
        sessionInterceptor.setAttributeNames(
                Arrays.asList("userId", "sessionData")
        );

        registry.addHandler(myHandler(), "/ws")
                .addInterceptors(sessionInterceptor);
    }
}

// Access attributes in handler
public class MyHandler extends TextWebSocketHandler {
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // Access HTTP session attributes
        String userId = (String) session.getAttributes().get("userId");
        String sessionData = (String) session.getAttributes().get("sessionData");

        System.out.println("User " + userId + " connected with data: " + sessionData);
    }
}

JSR-356 Endpoint with Spring Dependency Injection

import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

@Component
@ServerEndpoint("/chat")
public class ChatEndpoint {

    // Spring dependency injection works!
    @Autowired
    private MessageService messageService;

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connected: " + session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // Use injected service
        String response = messageService.processMessage(message);

        try {
            session.getBasicRemote().sendText(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println("Disconnected: " + session.getId());
    }

    @OnError
    public void onError(Session session, Throwable error) {
        System.err.println("Error: " + error.getMessage());
    }
}

Programmatic ServerEndpoint Registration

import org.springframework.web.socket.server.standard.ServerEndpointRegistration;
import jakarta.websocket.Endpoint;
import jakarta.websocket.EndpointConfig;

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointRegistration myEndpoint() {
        return new ServerEndpointRegistration("/programmatic", MyEndpoint.class)
                .setSubprotocols("chat", "superchat")
                .setEncoders(Arrays.asList(MessageEncoder.class))
                .setDecoders(Arrays.asList(MessageDecoder.class));
    }
}

class MyEndpoint extends Endpoint {
    @Override
    public void onOpen(Session session, EndpointConfig config) {
        session.addMessageHandler(new MessageHandler.Whole<String>() {
            @Override
            public void onMessage(String message) {
                try {
                    session.getBasicRemote().sendText("Echo: " + message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

Custom RequestUpgradeStrategy

import org.springframework.web.socket.server.RequestUpgradeStrategy;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "/ws")
                .setHandshakeHandler(handshakeHandlerWithCustomStrategy());
    }

    @Bean
    public HandshakeHandler handshakeHandlerWithCustomStrategy() {
        // Use Jetty-specific upgrade strategy
        RequestUpgradeStrategy strategy = new JettyRequestUpgradeStrategy();
        return new DefaultHandshakeHandler(strategy);
    }
}

WebSocketHandlerMapping Configuration

import org.springframework.web.socket.server.support.WebSocketHandlerMapping;
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;

@Configuration
public class WebSocketConfig {

    @Bean
    public WebSocketHandlerMapping webSocketHandlerMapping() {
        WebSocketHandlerMapping mapping = new WebSocketHandlerMapping();

        // Enable WebSocket upgrade matching to ensure only WebSocket
        // handshake requests (GET with "Upgrade: websocket" header)
        // are matched
        mapping.setWebSocketUpgradeMatch(true);

        // Configure lifecycle phase for ordered startup/shutdown
        mapping.setPhase(0);

        // Map WebSocket handlers to URL patterns
        Map<String, Object> urlMap = new HashMap<>();
        urlMap.put("/ws/chat", chatWebSocketHandler());
        urlMap.put("/ws/notifications", notificationWebSocketHandler());
        mapping.setUrlMap(urlMap);

        // Set handler order
        mapping.setOrder(1);

        return mapping;
    }

    @Bean
    public WebSocketHttpRequestHandler chatWebSocketHandler() {
        return new WebSocketHttpRequestHandler(
                new ChatWebSocketHandler(),
                new DefaultHandshakeHandler()
        );
    }

    @Bean
    public WebSocketHttpRequestHandler notificationWebSocketHandler() {
        return new WebSocketHttpRequestHandler(
                new NotificationWebSocketHandler(),
                new DefaultHandshakeHandler()
        );
    }
}

Configuring ServerContainer Properties

import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;

@Configuration
public class WebSocketConfig {

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container =
                new ServletServerContainerFactoryBean();

        // Set async send timeout (in milliseconds)
        container.setAsyncSendTimeout(30000L);

        // Set max session idle timeout (in milliseconds)
        container.setMaxSessionIdleTimeout(300000L);

        // Set max text message buffer size (in bytes)
        container.setMaxTextMessageBufferSize(8192);

        // Set max binary message buffer size (in bytes)
        container.setMaxBinaryMessageBufferSize(8192);

        return container;
    }
}