Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6406859

ObjectOutputStream.flush() doesnt flush

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P5 P5
    • None
    • 5.0
    • core-libs

      .FULL PRODUCT VERSION :
      java version "1.5.0_04"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0
      Java HotSpot(TM) Client VM (build 1.5.0_04-b05, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Windows XP Professional

      A DESCRIPTION OF THE PROBLEM :

      When an Object is written to an ObjectOutputStream and the flush method is called, not all the object attributes (I have spotted a Map) are written to the stream, where as Imuttable Objects such as String are. Flush should flush all objects linked to this object.

      I realise handles are kept in a map, this is OK, but the object in the stream should be written


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Use the code I provide, and run

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Cat before write:Name: Anthony has: all parts intact
      Cat after write:Name: Anthony written has: all parts intact
      Cat after read:Name: Anthony has: is not complete
      ACTUAL -
      Cat before write:Name: Anthony has: all parts intact
      Cat after write:Name: Anthony written has: all parts intact
      Cat after read:Name: Anthony has: all parts intact

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      //Separate callses into separate files
      //Cat.java

      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.ObjectInputStream;
      import java.io.ObjectOutputStream;
      import java.util.HashMap;
      import java.util.Map;

      public class Cat extends Animal{
      private static final long serialVersionUID = 1L;
      private Map attributes = new HashMap();

      public void setAttributes(){
      setName("Anthony");
      attributes.put(new Integer(0), "Right Back Leg");
      attributes.put(new Integer(1), "Right Front Leg");
      attributes.put(new Integer(2), "Left Back Leg");
      attributes.put(new Integer(3), "Left Front Leg");
      }

      public Map getAttributes() {
      return attributes;
      }

      public String toString(){
      String retVal = "Name: " + getName() + " has: ";
      if(attributes.size() == 4){
      retVal += " all parts intact";
      }else{
      retVal += " is not complete";
      }
      return retVal;
      }

      public static void main(String [] args){
      File serFile = null;
      try {
      Cat item = new Cat();
      item.setName("Anthony");
      item.setAttributes();
      item.setTranform(new CatTransform());

      System.out.println("Cat before write:" + item);

      serFile = File.createTempFile("cat", "ser");
      FileOutputStream fos = new FileOutputStream(serFile);
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(item);
      oos.close();
      fos.close();

      System.out.println("Cat after write:" + item);

      //
      // deserialize
      //

      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serFile));
      Cat itemread = (Cat) ois.readObject();
      ois.close();
      serFile.delete();

      System.out.println("Cat after read:" + itemread);

      }catch(Exception exp){
      exp.printStackTrace();
      }
      }
      }

      // Animal.java

      import java.io.IOException;
      import java.io.ObjectInputStream;
      import java.io.ObjectOutputStream;
      import java.io.Serializable;

      abstract class Animal implements Serializable{

      /**
      *
      */
      private String name;
      private transient Transform tranform;
      private static final long serialVersionUID = 1L;


      private void writeObject(ObjectOutputStream out)
      throws IOException, ClassCastException {

      Transform inverse = null;
      if(tranform != null)inverse = tranform.transform(this);

      out.defaultWriteObject();
      out.flush();

      if(inverse != null)inverse.transform(this);
      this.setName(this.getName() + " written");

      }

      private void readObject(ObjectInputStream in)
      throws IOException, ClassNotFoundException {
      in.defaultReadObject();
      }

      public void setTranform(Transform t){
      this.tranform = t;
      }

      /**
      * @return Returns the name.
      */
      public String getName() {
      return name;
      }

      /**
      * @param name The name to set.
      */
      public void setName(String name) {
      this.name = name;
      }

      }

      //Transform.java

      abstract class Transform{
      abstract Transform transform(Animal a);
      }

      // CatTransform.java

      import java.util.HashMap;
      import java.util.Map;

      class CatTransform extends Transform{
      Transform transform(Animal a){
      Cat cat = (Cat) a; // I can do this because I know the transform is used on Object of type Cat
      Map removed = new HashMap(cat.getAttributes());
      cat.getAttributes().clear(); //chop off all the cats legs
      return new InverseCatTransform(this,removed);
      }


      public static class InverseCatTransform extends Transform{
      private CatTransform inverse;
      private Map missing;

      public InverseCatTransform(CatTransform transform, Map removed) {
      inverse = transform;
      missing = removed;
      }

      Transform transform(Animal a){
      Cat cat = (Cat) a; // I can do this because I know the transform is used on Object of type Cat
      cat.getAttributes().putAll(missing);
      return inverse;
      }
      }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Implement Write replace in Animal instead, and clone the animal, then chop off the clones legs and return the dismembered clone.

      However this has performance implications as if I am sending say, 100 cats, and they all have the same mask, then I expect that my mask will only be written once to the stream. However with the clone I now have the overhead of 100 masks.

      The above example is a falacy, I am developing a dynamic transiencience of large objects. Our customer object may have thousands of attributes, I was to get back the customers names say I dont need the other 500 attributes so I create a transform and include it in the request, this then lops off the unessesary items...

            Unassigned Unassigned
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: