2 Replies Latest reply on May 24, 2010 2:58 PM by 843790

    StackOverflowError (due to infinite recursion) in XMLEncoder

    843790
      I try to save an Object (XmlEncoder.writeObject) which has a non default constructor (to restore the Object) and only public getter methods via XMLEncoder.
      Basically I'd like to save only the stuff needed in the extended constructor so I can restore the object with just one call to this constructor and not expose a lot of (unconvenient) setters (after all the XMLEncoder/Decoder would be the only one to use them). So I added:
      encoder.setPersistenceDelegate
      (
           Session.class,
           new DefaultPersistentDelegate(new String[]{"board", "robberPosition", "players", "active"})
      );
      The class looks like:
      public class Session
      {
           public Session();
      
           public Session(Board board, LandscapePosition robberPosition, Iterable<Player> players, Player active);
           
           public Session(Board board, LandscapePosition robberPosition, Iterable<Player> players, Session active);
           
           @Override
           public boolean equals(Object obj);
      
           public Object getActive();
           
           public LandscapePosition getRobberPosition();
      
           public Costs getCosts();
      
           public Board getBoard();
           
           public Collection<Player> getPlayers();
      
           public Player getActivePlayer();
      }
      What happens is my equals is called - but the parameter is null. So I assume there is some hidden policy in the XMLEncoder programming (did I mention that the docs are horrible?) I didn't get. I tried debugging through the code but there are several oddities I don't get (why is there a Statement generated for writeObject?, why is there no recursion checking mechanism?, why is mutatesTo described differently than it's implemented?, ...).
      Would be great if someone could shed some light into this dark alley.

      BTW the exception is:
      Exception in thread "main" java.lang.StackOverflowError
        at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:262)
        at java.beans.DefaultPersistenceDelegate.instantiate(DefaultPersistenceDelegate.java:158)
           
        at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:113)
        at java.beans.Encoder.writeObject(Encoder.java:74)
        at java.beans.XMLEncoder.writeObject(XMLEncoder.java:274)
        at java.beans.Encoder.writeObject1(Encoder.java:231)
        at java.beans.Encoder.cloneStatement(Encoder.java:244)
        at java.beans.Encoder.writeExpression(Encoder.java:303)
        at java.beans.XMLEncoder.writeExpression(XMLEncoder.java:389)
           
        at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:113)
        at java.beans.Encoder.writeObject(Encoder.java:74)
        at java.beans.XMLEncoder.writeObject(XMLEncoder.java:274)
        at java.beans.Encoder.writeObject1(Encoder.java:231)
        at java.beans.Encoder.cloneStatement(Encoder.java:244)
        at java.beans.Encoder.writeExpression(Encoder.java:303)
        at java.beans.XMLEncoder.writeExpression(XMLEncoder.java:389)
      Edited by: LCID_Fire on May 23, 2010 8:44 AM
        • 1. Re: StackOverflowError (due to infinite recursion) in XMLEncoder
          EJP
               @Override
               public boolean equals(Object obj);
          What's in here?
          why is there a Statement generated for writeObject?
          Because that's how it works.
          why is there no recursion checking mechanism?
          Because it shouldn't be needed. There isn't one in ObjectOutputStream either. Maybe it's you that's recursing?
          why is mutatesTo described differently than it's implemented?, ...).
          Hadn't noticed that. Details?
          Would be great if someone could shed some light into this dark alley.
          Have you read the [Swing Connnection articles|http://java.sun.com/products/jfc/tsc/articles/persistence2/] linked from the Javadoc?
          • 2. Re: StackOverflowError (due to infinite recursion) in XMLEncoder
            843790
            Finally after some prodding and debugging through the writeObject code I have it working.
            ejp wrote:
                 public boolean equals(Object obj);
            What's in here?
            I overrode all equals to be deep comparisons of the objects. One particular problem why these recursions happened were some wrong equals which returned false in the wrong situations. If there's just one equals in the cascade wrong you're very likely to encounter these recursions. Would there be a recursion check the classes could then throw an exception instead of blindly trying to do the same thing over and over.
            why is there no recursion checking mechanism?
            Because it shouldn't be needed. There isn't one in ObjectOutputStream either. Maybe it's you that's recursing?
            Would you care to elaborate why you think a recursion check is not needed? If I search for similar errors on google there are quite a few recursions occuring - all because people coded their beans differently than XMLEncoder was expecting.
            Imagine for example the following classes:
            public class Parent
            {
              public Parent(Collection<Child> children);
            }
            
            public class Child
            {
              public Child(Parent parent);
            
              public Parent getParent();
            }
            Attemting to save Parent would then again result in a infinite recursion.
            why is mutatesTo described differently than it's implemented?, ...).
            Hadn't noticed that. Details?
            Returns true if an equivalent copy of oldInstance may be created by applying a series of statements to newInstance
            What it really does is it checks whether newInstance IS already an equivalent copy of oldInstance. So I guess the whole wording is a little bit unprecise.
            Would be great if someone could shed some light into this dark alley.
            Have you read the [Swing Connnection articles|http://java.sun.com/products/jfc/tsc/articles/persistence2/] linked from the Javadoc?
            Yes. I have read everything I could get my hands on. And I know now why it's relatively sparse used (in contrast to the benefit it could be).

            Thanks for trying to help.