4

I know there are lot of questions on this topic. I have read the spring boot doc and all of the solutions here. According spring boot doc, @ServerEndpoint is a Javax annotation and @Autowired components are spring-boot managed. These two cannot be used together. The solution to this would be to add SpringConfigurator as configurator of the ServerEndpoint. When I tried this I do get the following error:

Failed to find the root WebApplicationContext. Was ContextLoaderListener not used?

There is no example in the spring-boot websocket page to use ContextLoaderListener. How can use ContextLoaderListener so that components can be injected into @ServerEndpoint annotated controllers?

The following is my code.

Websocket controller

@ServerEndpoint(value = "/call-stream", configurator = SpringConfigurator.class)
public class CallStreamWebSocketController
{  
    @Autowired
    private IntelligentResponseService responseServiceFacade;

    // Other methods
}

Websocket configurations

@Configuration
public class WebSocketConfiguration
{
    @Bean
    public CallStreamWebSocketController callStreamWebSocketController()
    {
        return new CallStreamWebSocketController();
    }

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

Edit: This has been tagged as a duplicate of this question. I have tried the solution specified in the answers. The solution is to add SpringConfigurator as configurator of the @ServerEndpoint. After adding this I still do get the error mentioned in the details.

Vino
  • 2,111
  • 4
  • 22
  • 42
  • Possible duplicate of [@ServerEndpoint and @Autowired](https://stackoverflow.com/questions/29306854/serverendpoint-and-autowired) – Shubham Dixit Oct 11 '18 at 12:02
  • I have referred that question. It says (like the spring boot doc) to add `SpringConfigurator` as the `@ServerEndpoint` configurator. As I have clearly said in the question, this does not work. – Vino Oct 11 '18 at 12:03
  • Did you add the mentioned spring-websocket dependency to the classpath? – Gimby Oct 11 '18 at 12:07
  • I am using spring-boot not spring. So I added `org.springframework.boot:spring-boot-starter-websocket` to my classpath. – Vino Oct 11 '18 at 12:09

1 Answers1

1

After some research I found a way to force spring-boot to inject a component into an externally managed/instantiated class.

1) Add a generic method to your class extending ApplicationContextAware to return a bean.

@Component
public class SpringContext implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        SpringContext.context = context;
    }

    public ApplicationContext getApplicationContext() {
        return context;
    }

    // Generic method to return a beanClass
    public static <T> T getBean(Class<T> beanClass)
    {
        return context.getBean(beanClass);
    }
}

2) Use this method to initialize the class object you want to be injected

private IntelligentResponseService responseServiceFacade = SpringContext.getBean(IntelligentResponseService.class);

So after the above changes my websocket controller would look like this

@ServerEndpoint(value = "/call-stream", configurator = SpringConfigurator.class)
public class CallStreamWebSocketController
{  
    private IntelligentResponseService responseServiceFacade = SpringContext.getBean(IntelligentResponseService.class);

    // Other methods
}
Vino
  • 2,111
  • 4
  • 22
  • 42
  • This is the only solution that works. There are some incompatibility issues with spring boot dependency injection and JSR356 annotation. – tonga Feb 19 '20 at 20:01
  • This results in a null pointer exception on SpringContext.context – bcr666 Jul 14 '23 at 12:54