Categories
discuss

Using Java API for WebSocket (JSR-356) with Spring Boot

I’m new to Spring (and asking questions on stackoverflow). I’d like to start an embedded (Tomcat) server via Spring Boot and register a JSR-356 WebSocket endpoint to it. This is the main method: @…

I’m new to Spring (and asking questions on stackoverflow).

I’d like to start an embedded (Tomcat) server via Spring Boot and register a JSR-356 WebSocket endpoint to it.

This is the main method:

@ComponentScan
@EnableAutoConfiguration
public class Server {
    public static void main(String[] args) {
        SpringApplication.run(Server.class, args);
    }
}

This is how the configuration looks:

@Configuration
public class EndpointConfig {

    @Bean
    public EchoEndpoint echoEndpoint() {
        return new EchoEndpoint();
    }

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

The EchoEndpoint implementation is straight-forward:

@ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class)
public class EchoEndpoint {

    @OnMessage
    public void handleMessage(Session session, String message) throws IOException {
        session.getBasicRemote().sendText("echo: " + message);
    }
}

For the second part I’ve followed this blog post: https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support.

However, when I run the application I get:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'endpointExporter' defined in class path resource [hello/EndpointConfig.class]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Failed to get javax.websocket.server.ServerContainer via ServletContext attribute

The exception is further caused by a NullPointerException in ServerEndpointExporter, because the getServletContext method on the applicationContext returns still null at this point.

Can somebody with a better understanding of Spring help me out? Thanks!

Answer

ServerEndpointExporter makes some assumptions about the lifecycle of an application context that don’t hold true when you’re using Spring Boot. Specifically, it’s assuming that when setApplicationContext is called, calling getServletContext on that ApplicationContext will return a non-null value.

You can work around the problem by replacing:

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

With:

@Bean
public ServletContextAware endpointExporterInitializer(final ApplicationContext applicationContext) {
    return new ServletContextAware() {

        @Override
        public void setServletContext(ServletContext servletContext) {
            ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter();
            serverEndpointExporter.setApplicationContext(applicationContext);
            try {
                serverEndpointExporter.afterPropertiesSet();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }               
        }           
    };
}

This defers the processing until the servlet context is available.

Update: You may like to watch SPR-12109. Once it’s fixed the workaround described above should no longer be necessary.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..