@ServerEndpoint and @Autowired
Asked Answered
P

5

6

How can I autowire a field into a @ServerEndpoint. The following does not work.

@Component
@ServerEndpoint("/ws")
public class MyWebSocket {   
    @Autowired
    private ObjectMapper objectMapper;
}

However if I remove the @ServerEndpoint, it works fine.

I am using spring 3.2.1 and Java 7

Perturbation answered 27/3, 2015 at 17:39 Comment(2)
Are you getting any error?Zawde
objectMapper is null. It is not injected/autowiredPerturbation
C
8

It seems that you are trying to integrate Spring and Java WebSocket API. A class annotated by @Component is registered to a spring bean and its instance is managed by spring as a singleton by default. However, a class annotated by @ServerEndpoint is registered to a server-side WebSocket endpoint and every time the corresponding endpoint's WebSocket is connected to the server, its instance is created and managed by JWA implementation. Therefore, you can't use both annotations together.

Maybe the simplest workaround is to use CDI instead of Spring. Of course, your server should support CDI.

@ServerEndpoint("/ws")
public class MyWebSocket {   
    @Inject
    private ObjectMapper objectMapper;
}

If it's not feasible to you, you can intercept instantiation process of the class annotated with ServerEndpoint by using a your own version of ServerEndpointConfig.Configurator. Then, you can instantiate the class by yourself and autowire it using an instance of BeanFactory or ApplicationContext. Actually, there is already similar answer to this usage. See that question and Martins' working example (Especially, a customized Configurator for integration with Spring).

Calculator answered 28/3, 2015 at 15:2 Comment(1)
Thanks for your answer. Very helpful. Though I just went ahead after updating to Spring 4 which has its own WebSocket impementation classesPerturbation
F
6

This issue could be fixed using SpringConfigurator (spring 4):

Add configurator to your ServerEndpoint:

@ServerEndpoint(value = "/ws", configurator = SpringConfigurator.class)

required maven dependency:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>${spring.version}</version>
</dependency>
Feudality answered 4/12, 2016 at 7:39 Comment(0)
Q
5

You should be able to just add this to your class actually.:

@PostConstruct
public void init(){
    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
Qualified answered 16/3, 2016 at 0:39 Comment(1)
That line worked if I added it my constructor, but not a postConstruct, which is not called by my javax websocket.Cosme
P
1

My solution was:

public WebsocketServletTest() {
      SpringApplicationListener.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(this);
}

where SpringApplicationListener is a ApplicationContextAware, which stores the context in a static variable

Potable answered 27/2, 2017 at 16:41 Comment(0)
E
0

JavaEE 7 specification says

@ServerEndpoint
The annotated class must have a public no-arg constructor.
Everetteverette answered 27/3, 2015 at 18:6 Comment(1)
I did not show in sample but there is already a default constructor in the class.Perturbation

© 2022 - 2024 — McMap. All rights reserved.