-
Bug
-
Resolution: Not an Issue
-
P5
-
None
-
5.0
-
x86
-
windows_xp
.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...
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...