interface ServletContextListener don't save state of ServletContext

244 views Asked by At

I have next websocket

@ServerEndpoint(value="/list")
public class WebSocketList implements ServletContextListener {

private ServletContextEvent sce;

@Override
public void contextInitialized(ServletContextEvent sce) {
    System.out.println("contextInitialized");
    this.sce = sce;
}

@OnMessage
public void receiveMessage(ByteBuffer bb, Session sn) {
    if (sce == null)
        System.out.println("not good");
}

File beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="annotated">
</beans>

In debug, the object ServletContextEvent in method contextInitialized was not null, but when I receive a message from client (in method receiveMessage), always logs "not good" - object ServletContextEvent is null.

UPDATE: When I add System.out.println(this) in both methods, logged next -

WebSocketList@da599a0 
WebSocketList@2942d8d0
1

There are 1 answers

0
Mike Laren On

I've just run into the same problem and as @Sotirios mentioned, the issue is that receivedMessage(ByteBuffer, Session) is called on a different object than contextInitialized(ServletContextEvent).

One way to fix it is by making your private ServletContextEvent sce field static but I suspect that doing so might cause problems when the context is stopped or reloaded. A better approach would be to extract all information that you need from the sce event and store it in one or more object fields.

In my case all I needed to store was the path of the current servlet context, so I just did this:

private static String path;

@Override
public void contextInitialized(ServletContextEvent sce) {
    this.path = sce.getServletContext().getContextPath();
}