IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

ObjectInputStream / readObject : ClassNotFoundException


Sujet :

Entrée/Sortie Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite

    Homme Profil pro
    Architecte technique
    Inscrit en
    Juin 2005
    Messages
    588
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2005
    Messages : 588
    Par défaut ObjectInputStream / readObject : ClassNotFoundException
    Bonjour,

    Dans mon appli, le code suivant lève une exception:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    // Try to unserialize byte buffer
    bis = new ByteArrayInputStream(b);
    ois = new ObjectInputStream(bis);
    Object ser = ois.readObject();
    java.lang.ClassNotFoundException: xxx
    at java.lang.Class.forName(Ljava.lang.String;ZLjava.lang.ClassLoader; )Ljava.lang.Class;(Unknown Source)
    at java.io.ObjectInputStream.resolveClass(Ljava.io.ObjectStreamClass; )Ljava.lang.Class;(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Z)Ljava.io.ObjectStreamClass;(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Z)Ljava.io.ObjectStreamClass;(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Z)Ljava.lang.Object;(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Z)Ljava.lang.Object;(Unknown Source)
    at java.io.ObjectInputStream.readObject()Ljava.lang.Object;(Unknown Source)

    Pour info:
    -> la classe xxx implémente biensur Serializable
    -> l'appli tourne sur Tomcat mais ici il ne s'agit ici que d'un accès à un fichier persistant (et non, d'un transfert http vers le client).
    -> l'objet en question est sérialisé via writeObject dans une session http.
    Lors d'un redémarrage de Tomcat, l'objet devrait être désérialisé (avant même le lancement de la servlet) afin de réaliser toute tâche interrompue lors de l'arrêt du serveur.

    Enfin
    -> Class cls = Thread.currentThread().getContextClassLoader().loadClass("xxx");
    charge bien la classe !

    Une idée ?
    Merci par avance...

  2. #2
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    je crois que, par défaut, objectinputstream s'en bat les couille du contextclassloader et utilise uniquement le bootstrapclass loader, à partir duquell les classes de ta webapp ne sont pas visible. une solution, c'est d'étendre objectinputstream et de surcharger resolveClass() et de toi même retrouver la classe à partir du context classloader.

  3. #3
    Membre émérite

    Homme Profil pro
    Architecte technique
    Inscrit en
    Juin 2005
    Messages
    588
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2005
    Messages : 588
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    je crois que, par défaut, objectinputstream s'en bat les couille du contextclassloader et utilise uniquement le bootstrapclass loader, à partir duquell les classes de ta webapp ne sont pas visible. une solution, c'est d'étendre objectinputstream et de surcharger resolveClass() et de toi même retrouver la classe à partir du context classloader.
    Après recherche, il semble que la méthode resolveClass() fait appel à latestUserDefinedLoader()...
    L'extention de ObjectOutputStream est peut être du luxe, si je fait un Thread.currentThread().setContextClassLoader() avant le readObject()... à tester !

    Merci pour ta réponse.

  4. #4
    Membre émérite

    Homme Profil pro
    Architecte technique
    Inscrit en
    Juin 2005
    Messages
    588
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2005
    Messages : 588
    Par défaut
    Shunter directement latestUserDefinedLoader() ne me semble pas si simple en définitive... j'ai donc suivi la piste de tchize_ !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    public class CustomObjectInputStream extends ObjectInputStream {
    		private ClassLoader classLoader;
     
    		public CustomObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
    			super(in);
    			this.classLoader = classLoader;
    		}
     
    		protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
    				ClassNotFoundException {			
    			return Class.forName(desc.getName(), false, classLoader);
    		}
    }
     
    ...
    ois = new CustomObjectInputStream(bis, Thread.currentThread().getContextClassLoader());
    Celà fonctionne correctement à condition que je supprime mes serialVersionUID (calculés à l'aide de serialver): en effet, dans le cas contraire, je me chope
    java.io.InvalidClassException: xxx; local class incompatible: stream classdesc serialVersionUID = 5724765844650135300, local class serialVersionUID = -6007020479808614644

    Cela, suppose donc que le serialVersionUID ne peut être fixé arbitrairement et/ou avec l'outil standard Comment le calculer alors ?

    a+

  5. #5
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Tu peux soit le fixer toi même et le changer quand ta classe change du point de vue de ses champs, ou laisser le compilatuer générer automatiquement en fonction des fields. Dans ton cas, le compilateur a probablement généré automatiquement, et le numéro généré pour les classe qui ont été utilisées lors de la sérialistion n'est pas le même que celui utilisé lors de la désérialisation:
    stream classdesc serialVersionUID = 5724765844650135300, local class serialVersionUID = -6007020479808614644

  6. #6
    Membre émérite

    Homme Profil pro
    Architecte technique
    Inscrit en
    Juin 2005
    Messages
    588
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2005
    Messages : 588
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Tu peux soit le fixer toi même et le changer quand ta classe change du point de vue de ses champs, ou laisser le compilatuer générer automatiquement en fonction des fields. Dans ton cas, le compilateur a probablement généré automatiquement, et le numéro généré pour les classe qui ont été utilisées lors de la sérialistion n'est pas le même que celui utilisé lors de la désérialisation:
    Bon sang quel !?@ que je suis... effectivement pour mes tests, j'utilisais de vieux fichiers de validation pour lesquels le serialVersionUID avait été fixé par le compilo encore merci pour la piste...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [RMI] ClassNotFoundException que je ne comprends tjs pas
    Par Satch dans le forum API standards et tierces
    Réponses: 4
    Dernier message: 10/05/2007, 12h07
  2. [EJB] ClassNotFoundException au déploiement
    Par rivierem dans le forum Java EE
    Réponses: 2
    Dernier message: 29/06/2004, 09h29
  3. [EJB] ClassNotFoundException au démarrage
    Par loulou dans le forum Java EE
    Réponses: 10
    Dernier message: 21/06/2004, 13h33
  4. [FileInputStream] readObject
    Par schousso dans le forum Entrée/Sortie
    Réponses: 10
    Dernier message: 27/05/2004, 15h21
  5. [ObjectInputStream]Pb avec GZIP et ByteArrayInputStream
    Par riloo dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 29/04/2004, 17h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo