Mahmoud Saleh
Mahmoud Saleh

Reputation: 33605

java.io.NotSerializableException: java.util.WeakHashMap

i am developing JSF2 application with spring framework on tomcat 7 and when stopping tomcat, i am getting the following exception:

SEVERE: IOException while loading persisted sessions: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.util.WeakHashMap
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.util.WeakHashMap
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at org.apache.catalina.session.StandardSession.readObject(StandardSession.java:1595)
    at org.apache.catalina.session.StandardSession.readObjectData(StandardSession.java:1060)
    at org.apache.catalina.session.StandardManager.doLoad(StandardManager.java:284)
    at org.apache.catalina.session.StandardManager.load(StandardManager.java:204)
    at org.apache.catalina.session.StandardManager.startInternal(StandardManager.java:491)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5390)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.io.NotSerializableException: java.util.WeakHashMap
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at org.apache.catalina.session.StandardSession.writeObject(StandardSession.java:1671)
    at org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:1077)
    at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:432)
    at org.apache.catalina.session.StandardManager.unload(StandardManager.java:353)
    at org.apache.catalina.session.StandardManager.stopInternal(StandardManager.java:518)
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
    at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5569)
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
    at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3919)
    at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:426)
    at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1345)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1530)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1519)
    ... 1 more

Dec 29, 2013 3:52:07 PM org.apache.catalina.session.StandardManager startInternal
SEVERE: Exception loading sessions from persistent storage
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.util.WeakHashMap
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at org.apache.catalina.session.StandardSession.readObject(StandardSession.java:1595)
    at org.apache.catalina.session.StandardSession.readObjectData(StandardSession.java:1060)
    at org.apache.catalina.session.StandardManager.doLoad(StandardManager.java:284)
    at org.apache.catalina.session.StandardManager.load(StandardManager.java:204)
    at org.apache.catalina.session.StandardManager.startInternal(StandardManager.java:491)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5390)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.io.NotSerializableException: java.util.WeakHashMap
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at org.apache.catalina.session.StandardSession.writeObject(StandardSession.java:1671)
    at org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:1077)
    at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:432)
    at org.apache.catalina.session.StandardManager.unload(StandardManager.java:353)
    at org.apache.catalina.session.StandardManager.stopInternal(StandardManager.java:518)
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
    at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5569)
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
    at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3919)
    at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:426)
    at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1345)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1530)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1519)
    ... 1 more

UPDATE: found that the only class in my app that uses WeakHashMap is the custom view scope class for spring as follows:

import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.PreDestroyViewMapEvent;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

public class ViewScope implements Scope, Serializable, HttpSessionBindingListener {

    private static final long serialVersionUID = -1483153100048704635L;
    private static final Logger LOGGER = LoggerFactory.getLogger(ViewScope.class);
    private final WeakHashMap<HttpSession, Set<ViewScopeViewMapListener>> sessionToListeners = new WeakHashMap<>();

    @Override
    public Object get(String name, ObjectFactory objectFactory) {
        Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
        // noinspection SynchronizationOnLocalVariableOrMethodParameter
        synchronized (viewMap) {
            if (viewMap.containsKey(name)) {
                return viewMap.get(name);
            } else {
                LOGGER.debug("Creating bean {}", name);
                Object object = objectFactory.getObject();
                viewMap.put(name, object);

                return object;
            }
        }
    }

    @Override
    public Object remove(String name) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String getConversationId() {
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        LOGGER.debug("registerDestructionCallback for bean {}", name);
        UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
        ViewScopeViewMapListener listener = new ViewScopeViewMapListener(viewRoot, name, callback, this);

        viewRoot.subscribeToViewEvent(PreDestroyViewMapEvent.class, listener);

        HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
        final Set<ViewScopeViewMapListener> sessionListeners;
        synchronized (sessionToListeners) {
            if (!sessionToListeners.containsKey(httpSession)) {
                sessionToListeners.put(httpSession, new HashSet<ViewScopeViewMapListener>());
            }
            sessionListeners = sessionToListeners.get(httpSession);
        }
        // noinspection SynchronizationOnLocalVariableOrMethodParameter
        synchronized (sessionListeners) {
            Set<ViewScopeViewMapListener> toRemove = new HashSet<>();
            for (ViewScopeViewMapListener viewMapListener : sessionListeners) {
                if (viewMapListener.checkRoot()) {
                    toRemove.add(viewMapListener);
                }
            }
            sessionListeners.removeAll(toRemove);
            sessionListeners.add(listener);
        }
        if (!FacesContext.getCurrentInstance().getExternalContext().getSessionMap().containsKey("sessionBindingListener")) {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("sessionBindingListener", this);
        }

    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        LOGGER.debug("Session event bound {}", event.getName());
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        LOGGER.debug("Session event unbound {}", event.getName());
        final Set<ViewScopeViewMapListener> listeners;
        synchronized (sessionToListeners) {
            if (sessionToListeners.containsKey(event.getSession())) {
                listeners = sessionToListeners.get(event.getSession());
                sessionToListeners.remove(event.getSession());
            } else {
                listeners = null;
            }
        }
        if (listeners != null) {
            for (ViewScopeViewMapListener listener : listeners) {
                listener.doCallback();
            }
        }
    }

    public void clearFromListener(ViewScopeViewMapListener listener) {
        LOGGER.debug("Removing listener from map");
        HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        if (httpSession != null) {
            synchronized (sessionToListeners) {
                if (sessionToListeners.containsKey(httpSession)) {
                    sessionToListeners.get(httpSession).remove(listener);
                }
            }
        }
    }

}

i don't know if i made the WeakHashMap transient will that affect the spring view scope or what ?

please advise how to solve this issue.

Upvotes: 1

Views: 1832

Answers (1)

Joachim Sauer
Joachim Sauer

Reputation: 308081

You get a java.io.NotSerializableException with the message java.util.WeakHashMap meaning that the WeakHashMap is not serializable.

From the stack trace one can see that Tomcat is trying to serialize a session (StandardSession.writeObjectData). That suggests that some attribute of your session is a WeakHashMap.

If you want your session to be serializable (which is useful for clustering and saving session data between server restarts), then you need to get rid of that (or wrap it in another object that handles the serialization correctly).

Either turn of session serialization, if you don't need it, or find out which attribute is the WeakHashMap (simply iterate over all of them and print the names of all WeakHashMap values).

Upvotes: 3

Related Questions