Description
Andy Wilkinson opened SPR-12109 and commented
This Boot app illustrates the problem:
package sample;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.socket.server.standard.SpringConfigurator;
@ComponentScan
@EnableAutoConfiguration
@Configuration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public EchoEndpoint echoEndpoint() {
return new EchoEndpoint();
}
@Bean
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
}
@ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class)
private static class EchoEndpoint {
@OnMessage
public void handleMessage(Session session, String message) throws IOException {
session.getBasicRemote().sendText("echo: " + message);
}
}
}
Running it fails with a NullPointerException
:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'endpointExporter' defined in class sample.Application: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Failed to get javax.websocket.server.ServerContainer via ServletContext attribute
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:232)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:618)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:467)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at sample.Application.main(Application.java:26)
Caused by: java.lang.IllegalStateException: Failed to get javax.websocket.server.ServerContainer via ServletContext attribute
at org.springframework.web.socket.server.standard.ServerEndpointExporter.getServerContainer(ServerEndpointExporter.java:113)
at org.springframework.web.socket.server.standard.ServerEndpointExporter.setApplicationContext(ServerEndpointExporter.java:86)
at org.springframework.context.support.ApplicationContextAwareProcessor.invokeAwareInterfaces(ApplicationContextAwareProcessor.java:119)
at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:94)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:407)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 14 more
Caused by: java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.socket.server.standard.ServerEndpointExporter.getServerContainer(ServerEndpointExporter.java:110)
... 20 more
ServerEndpointExporter
assumes that WebApplicationContext.getServletContext()
will return a non-null value when it's called from within setApplicationContext(context)
. This assumption doesn't hold true in a Boot application as the embedded Tomcat server hasn't been started yet.
A work around is to replace the ServerEndpointExporter
bean with the following:
@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 ServerEndpointExporter
's processing until a time when the ServletContext
is available
Affects: 4.0.6
Reference URL: http://stackoverflow.com/questions/25390100/using-java-api-for-websocket-jsr-356-with-spring-boot/25425384#25425384
Issue Links:
- Error running the application as WAR in tomcat 9 [SPR-17599] #22131 Error running the application as WAR in tomcat 9
- ServerEndpointExporter causes refresh to fail with java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available [SPR-12340] #16945 ServerEndpointExporter causes refresh to fail with java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
Referenced from: commits 379e5ab, 11805b6
Backported to: 4.0.7