HandshakeWebSocketService#initUpgradeStrategy does not check for the availability of relevant classes before attempting to instanciate StandardWebSocketUpgradeStrategy.


    static RequestUpgradeStrategy initUpgradeStrategy() {
        if (tomcatWsPresent) {
            return new TomcatRequestUpgradeStrategy();
        }
        else if (jettyWsPresent) {
            return new JettyRequestUpgradeStrategy();
        }
        else if (undertowWsPresent) {
            return new UndertowRequestUpgradeStrategy();
        }
        else if (reactorNettyPresent) {
            // As late as possible (Reactor Netty commonly used for WebClient)
            return ReactorNettyStrategyDelegate.forReactorNetty1();
        }
        else if (reactorNetty2Present) {
            // As late as possible (Reactor Netty commonly used for WebClient)
            return ReactorNettyStrategyDelegate.forReactorNetty2();
        }
        else {
            // Let's assume Jakarta WebSocket API 2.1+
            return new StandardWebSocketUpgradeStrategy();
        }
    }

This breaks when you attempt to load a context without a dependency on jakarta.websocket-client-api.

It looks like it should be handled gracefully by the following code in WebFluxConfigurationSupport:


    private WebSocketService initWebSocketService() {
        WebSocketService service = getWebSocketService();
        if (service == null) {
            try {
                service = new HandshakeWebSocketService();
            }
            catch (IllegalStateException ex) {
                // Don't fail, test environment perhaps
                service = new NoUpgradeStrategyWebSocketService();
            }
        }
        return service;
    }

but because a ClassNotFoundException is thrown instead of IllegalStateException; the context simply fails to load instead of falling back to NoUpgradeStrategyWebSocketService

Comment From: MFAshby

The workaround in my case was to add the following dependencies (my problem was loading a minimal context for a test case):

        <!-- SpringBootConfigStorageIntegrationTest loads the whole spring context, which winds up creating a 
             HandshakeWebSocketService, which falls back to jakarta websocket without testing if it's actually
             on the classpath -->
        <dependency>
            <groupId>jakarta.websocket</groupId>
            <artifactId>jakarta.websocket-api</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>jakarta.websocket</groupId>
            <artifactId>jakarta.websocket-client-api</artifactId>
            <scope>test</scope>
        </dependency>

Comment From: zhanyan-Ader1y

I created a new repository for this problem.

Class not found reason is jakarta.websocket dependency not passed down from webflux module.

Whether it is necessary to verify the existence of jakarta.websocket , and throw IllegalStateException?

optional("jakarta.websocket:jakarta.websocket-api") optional("jakarta.websocket:jakarta.websocket-client-api")