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

Langage Java Discussion :

Bug de sérialization avec writeReplace et ReadResolve ?


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 3
    Par défaut Bug de sérialization avec writeReplace et ReadResolve ?
    Bonjour,

    J'ai le soucis suivant avec la sérialization en Java, j'ai effectué quelques recherches sur Google mais personne ne semble avoir rencontré le meme probleme...

    J'essaie de sérializer des proxy CGLIB en les remplacant à la volée par des objets de transport lors de la sérialisation puis en recréant les proxy pendant la phase de déserialization. Pour faire cela j'utilise les fonctions writeReplace et readResolve prévues par l'algo de serialization Java.
    Pour illustrer le probleme, j'ai créé une classe de test qui est une version tres simplifiée de mon cas concret d'utilisation, mais qui reproduit bien le probleme qui semble etre un bug.
    Voici le code qui met en evidence le probleme :
    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
    import java.io.*;
    import java.util.Map;
    import java.util.HashMap;
     
    public class Main {
        public static void main(String[] args) {
            Main m = new Main();
            m.start();
        }
     
        static class Center implements Serializable {
            public User user;
            public String name;
        }
     
        static class User implements Serializable {
            public Center center;
            public String name;
            public Object writeReplace() {
                DataTransfer dt = new DataTransfer();
                dt.params.put("name", name);
                dt.params.put("center", center);
                return dt;
            }
        }
     
        static class DataTransfer implements Serializable {
            public Map<String, Object> params = new HashMap<String, Object>();
            public Object readResolve() {
                User user = new User();
                String name = (String) params.get("name");
                Center center = (Center) params.get("center");
                user.name = name;
                user.center = center;
                return user;
            }
        }
     
        public static <I> I serialize(I o) {
            try {
                ByteArrayOutputStream buf = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream(buf);
                out.writeObject(o);
                out.flush();
                out.close();
                ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()));
                Object dest = in.readObject(); // EXCEPTION LEVEE !!!
                in.close();
                return (I) dest;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
     
        private void start() {
            Center center = new Center();
            center.name = "centre1";
            User user = new User();
            user.name = "Dupont";
            user.center = center;
            center.user = user;
     
            User user1 = serialize(user);
            System.err.println("result : "+user1);
        }
    }
    L'execution de ce programme produit un ClassCastException.
    Il semble que le probleme vienne du fait que le graphe d'objets dans cet exemple est cyclique (tout fonctionne bien lorsqu'il n'est pas cyclique).
    En tracant au debugger, on dirait que la phase de sérialisation se passe bien, mais que pendant la désérialisation, selon quel objet est sérialisé en premier dans le graphe, certains objets ne sont pas bien résolus (ils restent dans leur classe de transport et la méthode readresolve n'est pas appelée)

    Si quelqu'un a une idee...

    Mael

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    156
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 156
    Par défaut
    C'est pas une question évidente, mais vu qu'un bout de code complet et fonctionnelle est fournis, j'ai un peu cherché.

    Pourquoi tu utilise une classe DataTransfer ? essaye voir de mettre la fonction readResolve() dans la classe User.

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 3
    Par défaut
    l'exemple est juste le code le plus concis que j'ai pu trouver qui reproduise mon probleme (ClassCastException car un objet du graphe n'est pas résolu pendant la désérilazation).

    En fait j'utilise "writeReplace" et "readResolve" dans un projet concret, pour pouvoir sérialiser entre 2 JVMs des classes générées dynamiquement avec CGLIB.
    Ces classes ne sont en effet pas sérializables (la classe étant créé dynamiquement sur 1 JVM elle n'est pas présente sur l'autre), et j'utilise donc ce mécanisme pour transformer a la volée les objets proxy en objets de transport, puis ces derniers sont ensuite reconvertis dans de nouveaux proxys dans la JVM destination (création de nouvelles classes dynamiques)

    Soit "A" mon objet proxy CGLIB non sérialization
    Soit "T" mon objet de transport (qui contient les données utiles)

    Etape de Sérialization :
    A.writeReplace() -> T

    Etape de Désérialization :
    T.readResolve() -> A

    Ce mécanisme fonctionne, c'est uniquement lorsque le graphe d'objets est cyclique (objet A qui reference B qui reference A...) que des problemes lors de la déserialization surviennent...

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    156
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 156
    Par défaut
    Pour ce qui est de serialiser les graph cyclique cela ne m'étonne pas trop que ça plante à vrai dire, et je suis désolé je ne sais pas trop comment faire pour échanger des données dans ton cas. Par contre il semble que cela fonctionne :

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    import java.util.List;
    import java.util.ArrayList;
    import java.io.*;
     
    public class T implements java.io.Serializable
    {
    	List<Link> lns;
    	String name;
    	T(String name)
    	{
    		this.name = name;
    		lns = new ArrayList<Link>();
    	}
    	public String toString()
    	{
    		return "[ "+ name +" ]";
    	}
    	public Link [] getLinks()
    	{
    		Link []res=new Link[0];
    		return lns.toArray(res);
    	}
    	public static void main(String []args) throws Exception
    	{
    		System.out.println("Creating one");
    		T one = new T("one");
    		System.out.println("Creating two");
    		T two = new T("two");
    		T three = new T("three");
    		System.out.println("Creating the link");
    		Link ln = new Link(one,two);
    		Link ln2 = new Link(two,three);
    		Link ln3 = new Link(one,three);
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(buf);
        out.writeObject(ln);
        out.flush();
        out.close();
        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()));
        Object dest = in.readObject(); // EXCEPTION LEVEE !!!
        in.close();
    		//System.out.println(dest);
    		for(T t : ((Link)dest).getSubObj())
    		{
    			for(Link l : t.getLinks())
    			{
    				System.out.println(l);
    			}
    		}
     
    	}
    }
     
    class Link implements java.io.Serializable
    {
    	T one;
    	T two;
    	Link(T t1,T t2)
    	{
    		one = t1 ; two = t2;
    		t1.lns.add(this);
    		t2.lns.add(this);
    	}
    	public String toString()
    	{
    		return "Link : " + one +" to " + two;
    	}
    	T []getSubObj()
    	{
    		return new T[]{one,two};
    	}
    }
    je peut rajouter à cela que je n'ai jamais vu readResolve renvoyer autre chose que la classe dont il fait partis :

    http://www.javalobby.org/java/forums/t17491.html

  5. #5
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    156
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 156
    Par défaut
    Pour plus de simplicité évite les classe interne, elle peuvent parfois nécessiter des cast un peu plus complexe

Discussions similaires

  1. Bugs à l'affichage avec IE7
    Par yiuche dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 28/12/2006, 15h02
  2. Bug internet explorer avec hotmail.com
    Par rub091 dans le forum IE
    Réponses: 8
    Dernier message: 31/05/2006, 09h21
  3. Gros bug SQL Server avec caractère "²"
    Par Oluha dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 26/05/2005, 14h31

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