The adapter support package provides implementations that bridge Spring's WebSocket API with native WebSocket runtime implementations. These adapters translate between Spring's unified WebSocket abstractions and platform-specific APIs like Jakarta WebSocket (JSR-356) and Jetty WebSocket.
Base class for WebSocket session implementations. Provides common functionality for managing session state, attributes, and message sending across different native WebSocket implementations.
import java.io.IOException;
import java.util.Map;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.adapter.NativeWebSocketSession;
/**
* Abstract base class for WebSocketSession implementations. Provides common
* session management functionality including attribute storage, message routing,
* and lifecycle management.
*
* @param <T> the native session type
* @since 4.0
*/
public abstract class AbstractWebSocketSession<T> implements NativeWebSocketSession {
/**
* Create a new instance and associate the given attributes with it.
*
* @param attributes the attributes from the HTTP handshake to associate
* with the WebSocket session; the provided attributes
* are copied, the original map is not used
*/
public AbstractWebSocketSession(Map<String, Object> attributes);
/**
* Return the map with attributes associated with the WebSocket session.
*/
@Override
public Map<String, Object> getAttributes();
/**
* Return the underlying native WebSocketSession.
*
* @return the native session object
*/
@Override
public T getNativeSession();
/**
* Return the underlying native WebSocketSession if it matches the
* required type.
*
* @param requiredType the required type of the native session
* @return the native session of the required type, or null if not
* available or not of the required type
*/
@Override
public <R> R getNativeSession(Class<R> requiredType);
/**
* Initialize the native session. This must be called before the session
* can be used.
*
* @param session the native session to initialize with
*/
public void initializeNativeSession(T session);
/**
* Send a WebSocket message. Routes to the appropriate send method based
* on message type (text, binary, ping, or pong).
*
* @param message the message to send
* @throws IOException if sending fails
*/
@Override
public final void sendMessage(WebSocketMessage<?> message) throws IOException;
/**
* Send a text message to the remote endpoint.
*
* @param message the text message to send
* @throws IOException if sending fails
*/
protected abstract void sendTextMessage(TextMessage message) throws IOException;
/**
* Send a binary message to the remote endpoint.
*
* @param message the binary message to send
* @throws IOException if sending fails
*/
protected abstract void sendBinaryMessage(BinaryMessage message) throws IOException;
/**
* Send a ping message to the remote endpoint.
*
* @param message the ping message to send
* @throws IOException if sending fails
*/
protected abstract void sendPingMessage(PingMessage message) throws IOException;
/**
* Send a pong message to the remote endpoint.
*
* @param message the pong message to send
* @throws IOException if sending fails
*/
protected abstract void sendPongMessage(PongMessage message) throws IOException;
/**
* Close the WebSocket connection with status 1000 (normal closure).
*
* @throws IOException if closing fails
*/
@Override
public final void close() throws IOException;
/**
* Close the WebSocket connection with the given status.
*
* @param status the close status
* @throws IOException if closing fails
*/
@Override
public final void close(CloseStatus status) throws IOException;
/**
* Perform the actual close operation with the native session.
*
* @param status the close status
* @throws IOException if closing fails
*/
protected abstract void closeInternal(CloseStatus status) throws IOException;
}Interface for accessing the underlying native WebSocket session object. Extends the standard WebSocketSession interface to provide access to platform-specific session implementations.
import org.springframework.web.socket.WebSocketSession;
/**
* A WebSocketSession that exposes the underlying native WebSocketSession
* through getters. Useful for accessing platform-specific features not
* available through the Spring abstraction.
*
* @since 4.0
*/
public interface NativeWebSocketSession extends WebSocketSession {
/**
* Return the underlying native WebSocketSession (e.g., Jakarta WebSocket
* Session, Jetty Session, etc.).
*
* @return the native session object
*/
Object getNativeSession();
/**
* Return the underlying native WebSocketSession if it matches the
* required type.
*
* @param requiredType the required type of the session
* @return the native session of the required type, or null if not
* available or not of the required type
*/
<T> T getNativeSession(Class<T> requiredType);
}The standard adapter package provides implementations for Jakarta WebSocket (formerly known as JSR-356), the standard WebSocket API for Java.
WebSocket session implementation for Jakarta WebSocket API. Adapts a Jakarta jakarta.websocket.Session to Spring's WebSocketSession interface.
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import jakarta.websocket.Session;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketExtension;
import org.springframework.web.socket.adapter.AbstractWebSocketSession;
/**
* A WebSocketSession for use with the standard WebSocket for Java API
* (Jakarta WebSocket).
*
* @since 4.0
*/
public class StandardWebSocketSession extends AbstractWebSocketSession<Session> {
/**
* Constructor for a standard WebSocket session.
*
* @param headers the headers of the handshake request
* @param attributes the attributes from the HTTP handshake to associate
* with the WebSocket session; the provided attributes
* are copied, the original map is not used
* @param localAddress the address on which the request was received
* @param remoteAddress the address of the remote client
*/
public StandardWebSocketSession(
HttpHeaders headers,
Map<String, Object> attributes,
InetSocketAddress localAddress,
InetSocketAddress remoteAddress);
/**
* Constructor that associates a user with the WebSocket session.
*
* @param headers the headers of the handshake request
* @param attributes the attributes from the HTTP handshake to associate
* with the WebSocket session
* @param localAddress the address on which the request was received
* @param remoteAddress the address of the remote client
* @param user the user associated with the session; if null we'll
* fall back on the user available in the underlying
* WebSocket session
*/
public StandardWebSocketSession(
HttpHeaders headers,
Map<String, Object> attributes,
InetSocketAddress localAddress,
InetSocketAddress remoteAddress,
Principal user);
/**
* Return a unique session identifier.
*/
@Override
public String getId();
/**
* Return the URI used to open the WebSocket connection.
*/
@Override
public URI getUri();
/**
* Return the headers used in the handshake request.
*/
@Override
public HttpHeaders getHandshakeHeaders();
/**
* Return the negotiated sub-protocol, or null if none was specified or
* negotiated successfully.
*/
@Override
public String getAcceptedProtocol();
/**
* Return the negotiated extensions, or an empty list if none.
*/
@Override
public List<WebSocketExtension> getExtensions();
/**
* Return the authenticated user for the session, if any.
*/
@Override
public Principal getPrincipal();
/**
* Return the address on which the request was received.
*/
@Override
public InetSocketAddress getLocalAddress();
/**
* Return the address of the remote client.
*/
@Override
public InetSocketAddress getRemoteAddress();
/**
* Configure the maximum size for an incoming text message.
*
* @param messageSizeLimit the maximum size in bytes
*/
@Override
public void setTextMessageSizeLimit(int messageSizeLimit);
/**
* Get the configured maximum size for an incoming text message.
*/
@Override
public int getTextMessageSizeLimit();
/**
* Configure the maximum size for an incoming binary message.
*
* @param messageSizeLimit the maximum size in bytes
*/
@Override
public void setBinaryMessageSizeLimit(int messageSizeLimit);
/**
* Get the configured maximum size for an incoming binary message.
*/
@Override
public int getBinaryMessageSizeLimit();
/**
* Return whether the connection is still open.
*/
@Override
public boolean isOpen();
/**
* Initialize the native Jakarta WebSocket session.
*
* @param session the Jakarta WebSocket session
*/
@Override
public void initializeNativeSession(Session session);
/**
* Send a text message to the remote endpoint.
*
* @param message the text message to send
* @throws IOException if sending fails
*/
@Override
protected void sendTextMessage(TextMessage message) throws IOException;
/**
* Send a binary message to the remote endpoint.
*
* @param message the binary message to send
* @throws IOException if sending fails
*/
@Override
protected void sendBinaryMessage(BinaryMessage message) throws IOException;
/**
* Send a ping message to the remote endpoint.
*
* @param message the ping message to send
* @throws IOException if sending fails
*/
@Override
protected void sendPingMessage(PingMessage message) throws IOException;
/**
* Send a pong message to the remote endpoint.
*
* @param message the pong message to send
* @throws IOException if sending fails
*/
@Override
protected void sendPongMessage(PongMessage message) throws IOException;
/**
* Close the WebSocket connection with the given status.
*
* @param status the close status
* @throws IOException if closing fails
*/
@Override
protected void closeInternal(CloseStatus status) throws IOException;
}Adapts a Spring WebSocketHandler to the Jakarta WebSocket API by extending jakarta.websocket.Endpoint. Handles message routing, lifecycle events, and error handling.
import java.nio.ByteBuffer;
import jakarta.websocket.CloseReason;
import jakarta.websocket.Endpoint;
import jakarta.websocket.EndpointConfig;
import jakarta.websocket.Session;
import org.springframework.web.socket.WebSocketHandler;
/**
* Adapts a WebSocketHandler to the standard WebSocket for Java API
* (Jakarta WebSocket). This class extends jakarta.websocket.Endpoint
* and delegates all lifecycle events to the Spring WebSocketHandler.
*
* @since 4.0
*/
public class StandardWebSocketHandlerAdapter extends Endpoint {
/**
* Create a new adapter for the given handler and session.
*
* @param handler the WebSocketHandler to adapt
* @param wsSession the StandardWebSocketSession to use
*/
public StandardWebSocketHandlerAdapter(
WebSocketHandler handler,
StandardWebSocketSession wsSession);
/**
* Called when the WebSocket connection is opened. Initializes the session
* and registers message handlers based on whether partial messages are
* supported. Then delegates to the WebSocketHandler's
* afterConnectionEstablished method.
*
* @param session the Jakarta WebSocket session
* @param config the endpoint configuration
*/
@Override
public void onOpen(Session session, EndpointConfig config);
/**
* Called when the WebSocket connection is closed. Delegates to the
* WebSocketHandler's afterConnectionClosed method.
*
* @param session the Jakarta WebSocket session
* @param reason the reason for closure
*/
@Override
public void onClose(Session session, CloseReason reason);
/**
* Called when a transport error occurs. Delegates to the
* WebSocketHandler's handleTransportError method.
*
* @param session the Jakarta WebSocket session
* @param exception the exception that occurred
*/
@Override
public void onError(Session session, Throwable exception);
}Adapter that converts a Jakarta WebSocket Extension to Spring's WebSocketExtension format.
import java.util.Map;
import jakarta.websocket.Extension;
import org.springframework.web.socket.WebSocketExtension;
/**
* A subclass of WebSocketExtension that can be constructed from a
* Jakarta WebSocket Extension. Adapts the Jakarta extension interface
* to Spring's extension representation.
*
* @since 4.0
*/
public class StandardToWebSocketExtensionAdapter extends WebSocketExtension {
/**
* Create a new adapter for the given Jakarta WebSocket extension.
*
* @param extension the Jakarta WebSocket extension to adapt
*/
public StandardToWebSocketExtensionAdapter(Extension extension);
}Adapter that converts a Spring WebSocketExtension to Jakarta WebSocket Extension format.
import java.util.List;
import jakarta.websocket.Extension;
import org.springframework.web.socket.WebSocketExtension;
/**
* Adapts an instance of Spring's WebSocketExtension to the Jakarta
* WebSocket Extension interface. Allows Spring extensions to be used
* with Jakarta WebSocket APIs.
*
* @since 4.0
*/
public class WebSocketToStandardExtensionAdapter implements Extension {
/**
* Create a new adapter for the given Spring WebSocketExtension.
*
* @param extension the Spring WebSocketExtension to adapt
*/
public WebSocketToStandardExtensionAdapter(WebSocketExtension extension);
/**
* Return the extension name.
*/
@Override
public String getName();
/**
* Return the extension parameters as a list of Parameter objects.
*/
@Override
public List<Extension.Parameter> getParameters();
}Base class for implementing Jakarta WebSocket Encoder and Decoder that delegate to Spring's ConversionService. This enables automatic conversion between domain objects and WebSocket message payloads.
import java.nio.ByteBuffer;
import jakarta.websocket.DecodeException;
import jakarta.websocket.Decoder;
import jakarta.websocket.EncodeException;
import jakarta.websocket.Encoder;
import jakarta.websocket.EndpointConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
/**
* Base class for implementing Jakarta WebSocket Encoder and/or Decoder.
* Provides encode and decode method implementations that delegate to a
* Spring ConversionService.
*
* By default, this class looks up a ConversionService registered in the
* active ApplicationContext under the name 'webSocketConversionService'.
* This works for both client and server endpoints in a Servlet container.
*
* Subclasses can extend this class and should also implement one or both
* of jakarta.websocket.Encoder and jakarta.websocket.Decoder. For
* convenience, BinaryEncoder, BinaryDecoder, TextEncoder, and TextDecoder
* subclasses are provided.
*
* Since JSR-356 only allows Encoder/Decoder to be registered by type,
* instances are managed by the WebSocket runtime and do not need to be
* registered as Spring Beans. They can, however, be injected with
* Spring-managed dependencies via @Autowired.
*
* @param <T> the type being converted to (for Encoder) or from (for Decoder)
* @param <M> the WebSocket message type (String or ByteBuffer)
* @since 4.0
*/
public abstract class ConvertingEncoderDecoderSupport<T, M> {
/**
* Called to initialize the encoder/decoder. If running in a
* Spring-managed context, performs autowiring of dependencies.
*
* @param config the endpoint configuration
*/
public void init(EndpointConfig config);
/**
* Called to destroy the encoder/decoder. Subclasses can override
* to perform cleanup.
*/
public void destroy();
/**
* Strategy method to obtain the ConversionService. By default, expects
* a bean named 'webSocketConversionService' in the active
* ApplicationContext. Override this method for custom lookup strategies.
*
* @return the ConversionService (never null)
*/
protected ConversionService getConversionService();
/**
* Returns the active ApplicationContext. By default, obtains the context
* via ContextLoader.getCurrentWebApplicationContext(). Override when not
* running in a Servlet container.
*
* @return the ApplicationContext or null
*/
protected ApplicationContext getApplicationContext();
/**
* Returns the type being converted. By default, resolved using generic
* type arguments of the class.
*
* @return the type descriptor for the conversion type
*/
protected TypeDescriptor getType();
/**
* Returns the WebSocket message type. By default, resolved using generic
* type arguments of the class.
*
* @return the type descriptor for the message type
*/
protected TypeDescriptor getMessageType();
/**
* Encode an object to a WebSocket message using the ConversionService.
*
* @param object the object to encode
* @return the encoded message
* @throws EncodeException if encoding fails
*/
public M encode(T object) throws EncodeException;
/**
* Determine if a given message can be decoded. Checks if the
* ConversionService supports the conversion.
*
* @param bytes the message to check
* @return true if the message can be decoded
*/
public boolean willDecode(M bytes);
/**
* Decode a WebSocket message into an object using the ConversionService.
*
* @param message the message to decode
* @return the decoded object
* @throws DecodeException if decoding fails
*/
public T decode(M message) throws DecodeException;
/**
* A binary Encoder that delegates to Spring's ConversionService.
* Extend this class to create a custom binary encoder.
*
* @param <T> the type that this Encoder can convert to
*/
public abstract static class BinaryEncoder<T>
extends ConvertingEncoderDecoderSupport<T, ByteBuffer>
implements Encoder.Binary<T> {
}
/**
* A binary Decoder that delegates to Spring's ConversionService.
* Extend this class to create a custom binary decoder.
*
* @param <T> the type that this Decoder can convert from
*/
public abstract static class BinaryDecoder<T>
extends ConvertingEncoderDecoderSupport<T, ByteBuffer>
implements Decoder.Binary<T> {
}
/**
* A text Encoder that delegates to Spring's ConversionService.
* Extend this class to create a custom text encoder.
*
* @param <T> the type that this Encoder can convert to
*/
public abstract static class TextEncoder<T>
extends ConvertingEncoderDecoderSupport<T, String>
implements Encoder.Text<T> {
}
/**
* A text Decoder that delegates to Spring's ConversionService.
* Extend this class to create a custom text decoder.
*
* @param <T> the type that this Decoder can convert from
*/
public abstract static class TextDecoder<T>
extends ConvertingEncoderDecoderSupport<T, String>
implements Decoder.Text<T> {
}
}The Jetty adapter package provides implementations for Eclipse Jetty's native WebSocket API.
WebSocket session implementation for Jetty WebSocket API. Adapts a Jetty org.eclipse.jetty.websocket.api.Session to Spring's WebSocketSession interface.
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.websocket.api.Session;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketExtension;
import org.springframework.web.socket.adapter.AbstractWebSocketSession;
/**
* A WebSocketSession for use with the Jetty WebSocket API.
*
* @since 4.0
*/
public class JettyWebSocketSession extends AbstractWebSocketSession<Session> {
/**
* Create a new JettyWebSocketSession instance.
*
* @param attributes the attributes from the HTTP handshake to associate
* with the WebSocket session
*/
public JettyWebSocketSession(Map<String, Object> attributes);
/**
* Create a new JettyWebSocketSession instance associated with the given
* user.
*
* @param attributes the attributes from the HTTP handshake to associate
* with the WebSocket session; the provided attributes
* are copied, the original map is not used
* @param user the user associated with the session; if null we'll
* fall back on the user available via Jetty's
* Session.getUpgradeRequest()
*/
public JettyWebSocketSession(Map<String, Object> attributes, Principal user);
/**
* Return a unique session identifier.
*/
@Override
public String getId();
/**
* Return the URI used to open the WebSocket connection.
*/
@Override
public URI getUri();
/**
* Return the headers used in the handshake request.
*/
@Override
public HttpHeaders getHandshakeHeaders();
/**
* Return the negotiated sub-protocol, or null if none was specified or
* negotiated successfully.
*/
@Override
public String getAcceptedProtocol();
/**
* Return the negotiated extensions, or an empty list if none.
*/
@Override
public List<WebSocketExtension> getExtensions();
/**
* Return the authenticated user for the session, if any.
*/
@Override
public Principal getPrincipal();
/**
* Return the address on which the request was received.
*/
@Override
public InetSocketAddress getLocalAddress();
/**
* Return the address of the remote client.
*/
@Override
public InetSocketAddress getRemoteAddress();
/**
* Configure the maximum size for an incoming text message.
*
* @param messageSizeLimit the maximum size in bytes
*/
@Override
public void setTextMessageSizeLimit(int messageSizeLimit);
/**
* Get the configured maximum size for an incoming text message.
*/
@Override
public int getTextMessageSizeLimit();
/**
* Configure the maximum size for an incoming binary message.
*
* @param messageSizeLimit the maximum size in bytes
*/
@Override
public void setBinaryMessageSizeLimit(int messageSizeLimit);
/**
* Get the configured maximum size for an incoming binary message.
*/
@Override
public int getBinaryMessageSizeLimit();
/**
* Return whether the connection is still open.
*/
@Override
public boolean isOpen();
/**
* Initialize the native Jetty WebSocket session.
*
* @param session the Jetty WebSocket session
*/
@Override
public void initializeNativeSession(Session session);
/**
* Send a text message to the remote endpoint.
*
* @param message the text message to send
* @throws IOException if sending fails
*/
@Override
protected void sendTextMessage(TextMessage message) throws IOException;
/**
* Send a binary message to the remote endpoint.
*
* @param message the binary message to send
* @throws IOException if sending fails
*/
@Override
protected void sendBinaryMessage(BinaryMessage message) throws IOException;
/**
* Send a ping message to the remote endpoint.
*
* @param message the ping message to send
* @throws IOException if sending fails
*/
@Override
protected void sendPingMessage(PingMessage message) throws IOException;
/**
* Send a pong message to the remote endpoint.
*
* @param message the pong message to send
* @throws IOException if sending fails
*/
@Override
protected void sendPongMessage(PongMessage message) throws IOException;
/**
* Close the WebSocket connection with the given status.
*
* @param status the close status
* @throws IOException if closing fails
*/
@Override
protected void closeInternal(CloseStatus status) throws IOException;
}Adapts a Spring WebSocketHandler to the Jetty WebSocket API by implementing org.eclipse.jetty.websocket.api.Session.Listener. Handles message routing, lifecycle events, and error handling.
import java.nio.ByteBuffer;
import org.eclipse.jetty.websocket.api.Callback;
import org.eclipse.jetty.websocket.api.Session;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
/**
* Adapts a WebSocketHandler to the Jetty WebSocket API by implementing
* Session.Listener. Delegates all lifecycle events to the Spring
* WebSocketHandler.
*
* @since 4.0
*/
public class JettyWebSocketHandlerAdapter implements Session.Listener {
/**
* Create a new adapter for the given handler and session.
*
* @param webSocketHandler the WebSocketHandler to adapt
* @param wsSession the JettyWebSocketSession to use
*/
public JettyWebSocketHandlerAdapter(
WebSocketHandler webSocketHandler,
JettyWebSocketSession wsSession);
/**
* Called when the WebSocket connection is opened. Initializes the session,
* demands the first frame, and delegates to the WebSocketHandler's
* afterConnectionEstablished method.
*
* @param session the Jetty WebSocket session
*/
@Override
public void onWebSocketOpen(Session session);
/**
* Called when a text message is received. Delegates to the
* WebSocketHandler's handleMessage method and demands the next frame.
*
* @param payload the text message payload
*/
@Override
public void onWebSocketText(String payload);
/**
* Called when a binary message is received. Delegates to the
* WebSocketHandler's handleMessage method and demands the next frame.
*
* @param payload the binary message payload
* @param callback the callback to invoke when processing is complete
*/
@Override
public void onWebSocketBinary(ByteBuffer payload, Callback callback);
/**
* Called when a pong message is received. Delegates to the
* WebSocketHandler's handleMessage method and demands the next frame.
*
* @param payload the pong message payload
*/
@Override
public void onWebSocketPong(ByteBuffer payload);
/**
* Called when the WebSocket connection is closed. Delegates to the
* WebSocketHandler's afterConnectionClosed method.
*
* @param statusCode the close status code
* @param reason the close reason phrase
* @param callback the callback to invoke when processing is complete
*/
@Override
public void onWebSocketClose(int statusCode, String reason, Callback callback);
/**
* Called when a transport error occurs. Delegates to the
* WebSocketHandler's handleTransportError method.
*
* @param cause the exception that occurred
*/
@Override
public void onWebSocketError(Throwable cause);
}Adapter that converts a Spring WebSocketExtension to Jetty's ExtensionConfig format.
import org.eclipse.jetty.websocket.api.ExtensionConfig;
import org.eclipse.jetty.websocket.common.JettyExtensionConfig;
import org.springframework.web.socket.WebSocketExtension;
/**
* Adapter class to convert a Spring WebSocketExtension to a Jetty
* ExtensionConfig. Extends JettyExtensionConfig to provide compatibility
* with Jetty's WebSocket API.
*
* @since 4.0
*/
public class WebSocketToJettyExtensionConfigAdapter extends JettyExtensionConfig {
/**
* Create a new adapter for the given Spring WebSocketExtension.
*
* @param extension the Spring WebSocketExtension to adapt
*/
public WebSocketToJettyExtensionConfigAdapter(WebSocketExtension extension);
}import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.NativeWebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import jakarta.websocket.Session;
public class NativeFeatureHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// Access native Jakarta WebSocket session for platform-specific features
if (session instanceof NativeWebSocketSession nativeSession) {
Session jakartaSession = nativeSession.getNativeSession(Session.class);
if (jakartaSession != null) {
// Use Jakarta-specific features
jakartaSession.setMaxIdleTimeout(300000); // 5 minutes
System.out.println("Native session ID: " + jakartaSession.getId());
}
}
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
session.sendMessage(new TextMessage("Echo: " + message.getPayload()));
}
}import java.nio.ByteBuffer;
import jakarta.websocket.EncodeException;
import org.springframework.web.socket.adapter.standard.ConvertingEncoderDecoderSupport;
public class PersonEncoder extends ConvertingEncoderDecoderSupport.TextEncoder<Person> {
// No additional code needed - encoding is handled automatically
// by the ConversionService
}
// Register the encoder in your endpoint configuration
import jakarta.websocket.server.ServerEndpointConfig;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointConfig.Configurator endpointConfigurator() {
return new ServerEndpointConfig.Configurator() {
@Override
public <T> T getEndpointInstance(Class<T> endpointClass)
throws InstantiationException {
// Configure encoders/decoders here
return super.getEndpointInstance(endpointClass);
}
};
}
@Bean
public ConversionService webSocketConversionService() {
DefaultConversionService service = new DefaultConversionService();
// Register custom converters for Person <-> String
service.addConverter(new PersonToStringConverter());
service.addConverter(new StringToPersonConverter());
return service;
}
}import java.nio.ByteBuffer;
import jakarta.websocket.DecodeException;
import org.springframework.web.socket.adapter.standard.ConvertingEncoderDecoderSupport;
public class ImageDecoder extends ConvertingEncoderDecoderSupport.BinaryDecoder<Image> {
// Decoding is handled automatically by the ConversionService
// Just register a ByteBuffer -> Image converter
}
// Converter implementation
import org.springframework.core.convert.converter.Converter;
public class ByteBufferToImageConverter implements Converter<ByteBuffer, Image> {
@Override
public Image convert(ByteBuffer source) {
byte[] bytes = new byte[source.remaining()];
source.get(bytes);
return Image.fromBytes(bytes);
}
}import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.NativeWebSocketSession;
import org.springframework.web.socket.adapter.jetty.JettyWebSocketSession;
import org.springframework.web.socket.adapter.standard.StandardWebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class AdaptiveHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
if (session instanceof StandardWebSocketSession) {
System.out.println("Using Jakarta WebSocket (JSR-356) implementation");
jakarta.websocket.Session nativeSession =
((NativeWebSocketSession) session).getNativeSession(
jakarta.websocket.Session.class);
// Configure Jakarta-specific settings
if (nativeSession != null) {
nativeSession.setMaxTextMessageBufferSize(128 * 1024);
}
} else if (session instanceof JettyWebSocketSession) {
System.out.println("Using Jetty WebSocket implementation");
org.eclipse.jetty.websocket.api.Session nativeSession =
((NativeWebSocketSession) session).getNativeSession(
org.eclipse.jetty.websocket.api.Session.class);
// Configure Jetty-specific settings
if (nativeSession != null) {
nativeSession.setMaxTextMessageSize(128 * 1024);
}
}
}
}import java.util.HashMap;
import java.util.Map;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.adapter.standard.StandardWebSocketSession;
import jakarta.websocket.Session;
public class SessionLifecycleExample {
public void createAndInitializeSession(
Session jakartaSession,
HttpHeaders headers,
InetSocketAddress localAddr,
InetSocketAddress remoteAddr) {
// Prepare attributes from handshake
Map<String, Object> attributes = new HashMap<>();
attributes.put("connectionTime", System.currentTimeMillis());
attributes.put("clientIp", remoteAddr.getAddress().getHostAddress());
// Create Spring WebSocket session wrapper
StandardWebSocketSession wsSession = new StandardWebSocketSession(
headers,
attributes,
localAddr,
remoteAddr
);
// Initialize with native session (must be called before use)
wsSession.initializeNativeSession(jakartaSession);
// Now the session is ready for use
System.out.println("Session ID: " + wsSession.getId());
System.out.println("URI: " + wsSession.getUri());
System.out.println("Protocol: " + wsSession.getAcceptedProtocol());
// Access session attributes
Long connectionTime = (Long) wsSession.getAttributes().get("connectionTime");
System.out.println("Connected at: " + connectionTime);
}
}import java.util.List;
import org.springframework.web.socket.WebSocketExtension;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class ExtensionAwareHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// Check negotiated extensions
List<WebSocketExtension> extensions = session.getExtensions();
for (WebSocketExtension extension : extensions) {
System.out.println("Extension: " + extension.getName());
// Check for specific extension
if ("permessage-deflate".equals(extension.getName())) {
System.out.println("Compression is enabled");
// Access extension parameters
String serverNoContextTakeover =
extension.getParameter("server_no_context_takeover");
System.out.println("Server no context takeover: " +
serverNoContextTakeover);
}
}
}
}import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter;
import org.springframework.web.socket.adapter.standard.StandardWebSocketSession;
import org.springframework.http.HttpHeaders;
import jakarta.websocket.server.ServerEndpointConfig;
public class EndpointConfiguration {
public void configureEndpoint(
WebSocketHandler handler,
HttpHeaders headers,
Map<String, Object> attributes) {
// Create Spring WebSocket session
StandardWebSocketSession wsSession = new StandardWebSocketSession(
headers,
attributes,
null, // local address
null // remote address
);
// Create adapter to bridge Spring handler to Jakarta API
StandardWebSocketHandlerAdapter adapter =
new StandardWebSocketHandlerAdapter(handler, wsSession);
// The adapter can now be used as a Jakarta WebSocket Endpoint
// It will receive Jakarta WebSocket events and delegate to
// the Spring WebSocketHandler
}
}