java.lang.IllegalStateException: ServletConfig has not been initialized

user2133558 picture user2133558 · Mar 22, 2016 · Viewed 9.3k times · Source

I am trying to create an UI component that allow the user to customize the timeout of sessions. So I created a servlet as below:

public class SessionTimeoutServlet extends AbstractBaseServlet {
    private static final long serialVersionUID = 2567293974465204729L;

    public static final String REQUEST_TIMEOUT_PARAMETR_NAME = "timeout";
    private static final String TIMEOUT_TYPE_INIT_PARAMETER_NAME = "timeoutType";
    private static final String WEB_TYPE_TIMEOUT = "web";
    private static final String WEBSERVICE_TYPE_TIMEOUT = "webService";

    @EJB(mappedName = SessionSettingsRemote.BEAN_NAME)
    private SessionSettingsRemote sessionSettingsBean;

    @PostConstruct
    public void initTimeout() {
        try {
            String timeoutType = getServletContext().getInitParameter(TIMEOUT_TYPE_INIT_PARAMETER_NAME);
            if (WEBSERVICE_TYPE_TIMEOUT.equals(timeoutType)) {
                setCustomTimeout(sessionSettingsBean.getSessionSettingsDTO().getWebServiceSessionTimeoutInterval());
            } else if (WEB_TYPE_TIMEOUT.equals(timeoutType)) {
                setCustomTimeout(sessionSettingsBean.getSessionSettingsDTO().getWebSessionTimeoutInterval());
            } else {
                setCustomTimeout(30);
            }
        } catch (ApplicationException e) {
            setCustomTimeout(30);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int timeout = Integer.parseInt(request.getParameter(REQUEST_TIMEOUT_PARAMETR_NAME));
        setCustomTimeout(timeout);
    }

    public static void setCustomTimeout(int customTimeout) {
        SessionManagerListener.setCustomTimeout(customTimeout);
    }

}

However, when I deploy this on GlassFish, I get below exception.

Caused by: java.lang.IllegalStateException: ServletConfig has not been initialized
    at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:199)
    at com.accedian.ems.uiapplication.server.servlets.SessionTimeoutServlet.initTimeout(SessionTimeoutServlet.java:33)
    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:497)
    at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl$3.run(InjectionManagerImpl.java:766)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.invokeLifecycleMethod(InjectionManagerImpl.java:760)
    at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:531)
    at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:141)
    at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:127)
    at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:347)
    at com.sun.enterprise.web.WebContainer.createServletInstance(WebContainer.java:991)
    at com.sun.enterprise.web.WebModule.createServletInstance(WebModule.java:2130)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1404)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1381)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5732)

I have used getServletConfig() before getServletContext() but it was null. So why is my config and context are not properly set ?

Answer

BalusC picture BalusC · Mar 23, 2016

Servlets predate managed beans and annotations and all the fancy stuff you see since Java EE 6. Previously, you have to explicitly implement a predefined abstract/template method in order to perform a task at a certain moment in the lifecycle.

For servlets, in order to hook on its initialization the same way you'd use @PostConstruct on a "normal" managed bean, you have to override the predefined GenericServlet#init() method.

@Override
public void init() {
    // ...
}

The getServletContext() will be available there.

If you pay attention to the GenericServlet javadoc, you'll notice that there's also an init(ServletConfig). It's however strongly recommended to not use that method, but use init() instead. The default implementation of init(ServletConfig) namely takes care that the ServletContext is properly set. You'd have to mind calling super.init(config) to not make the same mistake. As a historical note, see that the canonical name of a @PostConstruct method as you see on managed beans, "init", is inherited from exactly this Servlet API.

In case you wonders, the @PreDestroy equivalent is the GenericServlet#destroy() method.

@Override
public void destroy() {
    // ...
}