web-dev-qa-db-fra.com

Quelles sont les causes d'une exception NotSerializableException dans Tomcat 7?

Mon implémentation DAO lève une exception non sérialisable au démarrage du serveur avec Tomcat7. Une idée de ce qui cause ça? Aucun de mes autres DAO ne fait cela.

Voici la classe:

package com.project.dao;

import Java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.project.model.User;

public class UserDAOImpl implements UserDAO {
    private HibernateTemplate hibernateTemplate;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

    @Override
    public void saveUser(User user) {
        hibernateTemplate.saveOrUpdate(user);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<User> listUser() {
        return hibernateTemplate.find("from User");
    }

    @Override
    @SuppressWarnings("unchecked")
    public User getUserByID(long userID) {
        List<User> users= hibernateTemplate.find("from User where id = '" + userID + "'");
        return users.size() > 0 ? users.get(0) : null;
    }
}

Voici ma config:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    <bean id="myDataSource" 
    class="org.Apache.Tomcat.dbcp.dbcp.BasicDataSource">
      <property name="driverClassName">
        <value>com.mysql.jdbc.Driver</value>
      </property>
      <property name="url">
        <value>jdbc:mysql://localhost/context</value>
      </property>
      <property name="username">
        <value>someUser</value>
      </property>
      <property name="password">
        <value>somePassword</value>
      </property>
      <!-- Disable the second-level cache  -->
        <!-- Echo all executed SQL to stdout -->
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="myDataSource" /> 
        <property name="annotatedClasses">
            <list>
                <value>com.project.model.User</value>
            </list>
        </property> 
        <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
        </property>
    </bean>
    <bean id="myUserDAO" class="com.project.dao.UserDAOImpl">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean> 
</beans>

Voici ma pile:

SEVERE: IOException while loading persisted sessions: Java.io.WriteAbortedException: writing aborted; Java.io.NotSerializableException: com.news.dao.UserDAOImpl
Java.io.WriteAbortedException: writing aborted; Java.io.NotSerializableException: com.project.dao.UserDAOImpl

at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1332)
at Java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.Java:1946)
at Java.io.ObjectInputStream.readSerialData(ObjectInputStream.Java:1870)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1752)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.Java:1946)
at Java.io.ObjectInputStream.readSerialData(ObjectInputStream.Java:1870)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1752)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.Java:1946)
at Java.io.ObjectInputStream.readSerialData(ObjectInputStream.Java:1870)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1752)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.readObject(ObjectInputStream.Java:350)
at org.Apache.catalina.session.StandardSession.readObject(StandardSession.Java:1600)
at org.Apache.catalina.session.StandardSession.readObjectData(StandardSession.Java:1073)
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:470)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.StandardContext.startInternal(StandardContext.Java:5241)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.ContainerBase.startInternal(ContainerBase.Java:1033)
at org.Apache.catalina.core.StandardHost.startInternal(StandardHost.Java:774)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.ContainerBase.startInternal(ContainerBase.Java:1033)
at org.Apache.catalina.core.StandardEngine.startInternal(StandardEngine.Java:291)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.StandardService.startInternal(StandardService.Java:443)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.StandardServer.startInternal(StandardServer.Java:727)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.startup.Catalina.start(Catalina.Java:620)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:39)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:25)
at Java.lang.reflect.Method.invoke(Method.Java:597)
at org.Apache.catalina.startup.Bootstrap.start(Bootstrap.Java:303)
at org.Apache.catalina.startup.Bootstrap.main(Bootstrap.Java:431)

Caused by: Java.io.NotSerializableException: com.project.dao.UserDAOImpl
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1164)
at Java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.Java:1518)
at Java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.Java:1483)
at Java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.Java:1400)
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1158)
at Java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.Java:1518)
at Java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.Java:1483)
at Java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.Java:1400)
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1158)
at Java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.Java:1518)
at Java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.Java:1483)
at Java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.Java:1400)
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1158)
at Java.io.ObjectOutputStream.writeObject(ObjectOutputStream.Java:330)
at org.Apache.catalina.session.StandardSession.writeObject(StandardSession.Java:1676)
at org.Apache.catalina.session.StandardSession.writeObjectData(StandardSession.Java:1090)
at org.Apache.catalina.session.StandardManager.doUnload(StandardManager.Java:411)
at org.Apache.catalina.session.StandardManager.unload(StandardManager.Java:353)
at org.Apache.catalina.session.StandardManager.stopInternal(StandardManager.Java:497)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.StandardContext$4.run(StandardContext.Java:5464)
at Java.lang.Thread.run(Thread.Java:662)
at org.Apache.catalina.core.StandardContext.stopInternal(StandardContext.Java:5481)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.ContainerBase.stopInternal(ContainerBase.Java:1072)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.ContainerBase.stopInternal(ContainerBase.Java:1072)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.StandardService.stopInternal(StandardService.Java:502)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.StandardServer.stopInternal(StandardServer.Java:748)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.startup.Catalina.stop(Catalina.Java:693)
at org.Apache.catalina.startup.Catalina.start(Catalina.Java:654)
... 6 more
Jul 31, 2011 9:27:21 PM org.Apache.catalina.session.StandardManager startInternal

SEVERE: Exception loading sessions from persistent storage
Java.io.WriteAbortedException: writing aborted; Java.io.NotSerializableException: com.project.dao.UserDAOImpl
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1332)
at Java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.Java:1946)
at Java.io.ObjectInputStream.readSerialData(ObjectInputStream.Java:1870)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1752)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.Java:1946)
at Java.io.ObjectInputStream.readSerialData(ObjectInputStream.Java:1870)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1752)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.Java:1946)
at Java.io.ObjectInputStream.readSerialData(ObjectInputStream.Java:1870)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1752)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.readObject(ObjectInputStream.Java:350)
at org.Apache.catalina.session.StandardSession.readObject(StandardSession.Java:1600)
at org.Apache.catalina.session.StandardSession.readObjectData(StandardSession.Java:1073)
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:470)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.StandardContext.startInternal(StandardContext.Java:5241)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.ContainerBase.startInternal(ContainerBase.Java:1033)
at org.Apache.catalina.core.StandardHost.startInternal(StandardHost.Java:774)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.ContainerBase.startInternal(ContainerBase.Java:1033)
at org.Apache.catalina.core.StandardEngine.startInternal(StandardEngine.Java:291)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.StandardService.startInternal(StandardService.Java:443)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.core.StandardServer.startInternal(StandardServer.Java:727)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
at org.Apache.catalina.startup.Catalina.start(Catalina.Java:620)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:39)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:25)
at Java.lang.reflect.Method.invoke(Method.Java:597)
at org.Apache.catalina.startup.Bootstrap.start(Bootstrap.Java:303)
at org.Apache.catalina.startup.Bootstrap.main(Bootstrap.Java:431)

Caused by: Java.io.NotSerializableException: com.project.dao.UserDAOImpl
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1164)
at Java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.Java:1518)
at Java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.Java:1483)
at Java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.Java:1400)
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1158)
at Java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.Java:1518)
at Java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.Java:1483)
at Java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.Java:1400)
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1158)
at Java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.Java:1518)
at Java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.Java:1483)
at Java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.Java:1400)
at Java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.Java:1158)
at Java.io.ObjectOutputStream.writeObject(ObjectOutputStream.Java:330)
at org.Apache.catalina.session.StandardSession.writeObject(StandardSession.Java:1676)
at org.Apache.catalina.session.StandardSession.writeObjectData(StandardSession.Java:1090)
at org.Apache.catalina.session.StandardManager.doUnload(StandardManager.Java:411)
at org.Apache.catalina.session.StandardManager.unload(StandardManager.Java:353)
at org.Apache.catalina.session.StandardManager.stopInternal(StandardManager.Java:497)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.StandardContext$4.run(StandardContext.Java:5464)
at Java.lang.Thread.run(Thread.Java:662)
at org.Apache.catalina.core.StandardContext.stopInternal(StandardContext.Java:5481)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.ContainerBase.stopInternal(ContainerBase.Java:1072)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.ContainerBase.stopInternal(ContainerBase.Java:1072)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.StandardService.stopInternal(StandardService.Java:502)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.core.StandardServer.stopInternal(StandardServer.Java:748)
at org.Apache.catalina.util.LifecycleBase.stop(LifecycleBase.Java:225)
at org.Apache.catalina.startup.Catalina.stop(Catalina.Java:693)
at org.Apache.catalina.startup.Catalina.start(Catalina.Java:654)
... 6 more
21
coder

UserDaoImpl doit implémenter l'interface Java.io.Serializable si elle doit être sérialisée (votre trace de pile indique qu'une tentative est faite pour écrire une instance de la classe dans un flux d'objets).

L'instance à sérialiser, ainsi que tous les objets du graphe d'objets de cette instance, doivent tous être sérialisables.

Depuis les javadocs pour Serializable,

La sérialisation d'une classe est activée par la classe implémentant l'interface Java.io.Serializable ... Lors de la traversée d'un graphe, un objet peut ne pas être pris en charge par l'interface Serializable. Dans ce cas, NotSerializableException sera levée et identifiera la classe de l'objet non sérialisable.

Notez qu'il existe des exceptions à ces règles. Je vous recommande de lire Java Object Serialization Specification pour bien comprendre quand la sérialisation d'objet a lieu et ce qu'il faut pour éviter une NotSerializableException.

21
Brandon E Taylor

Cela se produit car quelque part dans votre code, vous stockez un UserDAO dans la session (ou vous stockez un objet qui a une référence à un UserDAO). Tomcat essaie de sérialiser le graphique d'objet complet de toutes les sessions actives lorsque vous le fermez, puis il essaie de les restaurer lorsque vous le redémarrez. Le nœud du problème est que Tomcat utilise "normal" Java sérialisation d'objet, qui requiert que tous les objets soient Serializable.

Comment y remédier:

  1. Ne stockez pas d'objets non sérialisables dans la session des utilisateurs (généralement une bonne pratique).
  2. Rendez votre UserDAO sérialisable. Implique probablement l'implémentation de l'interface Serializable et le marquage de votre hibernateTemplate comme transient car je ne pense pas que HibernateTemplate soit, en soi, sérialisable. Vous devrez peut-être ajouter du code qui réinitialise le hibernateTemplate sur la désérialisation si vous voulez vraiment que cela fonctionne.
  3. Ne pas avoir de sessions de sérialisation Tomcat (ajoutez <Manager pathname="" /> au context.xml, soit dans votre propre application, soit dans le contexte global Tomcat context.xml dans le répertoire conf /, à l'intérieur du <Context> élément. Cela pourrait être la meilleure solution pour vous, à moins que vous n'ayez vraiment besoin que les sessions soient persistantes lors des redémarrages.
32
pap

Les autres réponses ici expliquent bien la sérialisation. Comme il s'agit du premier résultat dans Google, je voulais ajouter des informations qui m'ont vraiment aidé à résoudre le problème.

Le message d'exception lui-même n'indique pas quel champ dans quelle classe a provoqué ce problème. Si vous ne pouvez pas rendre une classe sérialisable et devez ajouter le mot-clé transitoire, donc Java n'essaie pas de sérialiser un champ, il peut être difficile de déterminer quel champ est à l'origine du problème.

Si vous ajoutez le paramètre -Dsun.io.serialization.extendedDebugInfo=true à Java/Tomcat au démarrage, l'exception sera beaucoup plus utile. Voici un exemple de ce à quoi ressemblera le message d'exception:

Java.io.NotSerializableException: za.co.abc.presentation.control.Three
 - field (class "za.co.abc.presentation.control.Two", name: "three", type: "class za.co.abc.presentation.control.Three")
 - object (class "za.co.abc.presentation.control.Two", za.co.abc.presentation.control.Two@fbbb20)
 - field (class "za.co.abc.presentation.control.One", name: "two", type: "class za.co.abc.presentation.control.Two")
 - object (class "za.co.abc.presentation.control.One", za.co.abc.presentation.control.One@17ee6c9)
 - field (class "za.co.abc.presentation.control.Trail", name: "one", type: "class za.co.abc.presentation.control.One")
 - root object (class "za.co.abc.presentation.control.Trail", {/click-tests/home.htm=home})

Si vous utilisez le mot-clé transitoire pour que les champs ne soient pas sérialisés, vous devrez probablement définir ces champs lors de la lecture de la classe. Vous devez implémenter la méthode readObject () pour ce faire. Voici un exemple:

private void readObject(Java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
    // magically read all non-transient fields from input stream and populate their values
    in.defaultReadObject();

    someTransientField = new NotSerializableClass();
}
13
Sarel Botha