Dear Wiki user,

You have subscribed to a wiki page or wiki category on "River Wiki" for change 
notification.

The "Serialization" page has been changed by PeterFirmstone:
http://wiki.apache.org/river/Serialization?action=diff&rev1=8&rev2=9

  }
  }}}
  
- === Circularity ===
+ == Circularity Issue ==
  The Serialization Builder takes advantage of the readResolve() method to 
replace itself with a newly built object after the builder is deserialized.  
The java serialization specification describes an issue with circular 
references:
  
  ''Note - The readResolve method is not invoked on the object until the object 
is fully constructed, so any references to this object in its object graph will 
not be updated to the new object nominated by readResolve. However, during the 
serialization of an object with the writeReplace method, all references to the 
original object in the replacement object's object graph are replaced with 
references to the replacement object. Therefore in cases where an object being 
serialized nominates a replacement object whose object graph has a reference to 
the original object, deserialization will result in an incorrect graph of 
objects. Furthermore, if the reference types of the object being read 
(nominated by writeReplace) and the original object are not compatible, the 
construction of the object graph will raise a ClassCastException. ''
  
  [[http://blog.crazybob.org/|Bob Lee]] is credited with the following work 
around:
  
- Have the builder implement the same interface and have it delegate to a 
transient copy of the built object... example soon.
+ Have the builder implement the same interface and have it delegate to a 
transient copy of the built object.
  
+ So the Serialization Builder above would need the following modifications:
+ 
+ === The Abstract Builder with readResolve workaround ===
+ {{{
+ public abstract class Builder extends AbstractMap{
+ 
+     public static Builder new(){
+         return new SerializationBuilderImp();
+     }
+    
+     public abstract Map build();
+ 
+ }
+ }}}
+ 
+ === The Serialization Builder Implementation with readResolve workaround ===
+ {{{
+ class SerializationBuilderImp extends Builder implements Serializable {
+ 
+     private Map mutableMap = new HashMap();
+     private transient Map serialBuilt = null;
+     
+     public Object put(Object key, Object value){
+         if ( serialBuilt != null ) return serialBuilt.put(key, value);
+         return mutableMap.put(key, value);
+     }
+ 
+     public Set entrySet(){
+         if ( serialBuilt != null ) return serialBuilt.entrySet();
+         return mutableMap.entrySet();
+     }
+ 
+     public Map build(){
+         return new ImmutableMap(mutableMap);
+     }
+ 
+     private void readObject(ObjectInputStream in)
+       throws IOException, ClassNotFoundException {
+       in.defaultReadObject();
+     }
+     
+     private void writeObject(ObjectOutputStream out) throws IOException {
+         out.defaultWriteObject();
+     }
+ 
+     private Object readResolve(){
+         serialBuilt = build();
+         return serialBuilt;
+     }
+ }
+ }}}
+ === Package private Map implementation ===
+ {{{
+ class ImmutableMap extends AbstractMap implements Map, Serializable {
+ 
+     private final Map immutable;
+     
+     ImmutableMap( Map map ){
+         Map newMap = new HashMap(map.size());
+         newMap.putAll(map);
+         immutable = Collections.unmodifiableMap(newMap);
+     }
+ 
+     public Set entrySet(){
+         return immutable.entrySet();
+     }
+ 
+     private Object writeReplace() {
+         // returns a Builder instead of this class.
+         Map builder = Builder.new();
+         builder.putAll(immutable);
+         return builder; // note build() method is not called until 
deserialisation.
+     }
+     
+     private void readObject(ObjectInputStream stream) 
+             throws InvalidObjectException{
+         throw new InvalidObjectException("Builder required");
+     }
+     
+ }
+ }}}
+ 
+ The examples here are relatively simplistic, it is possible to have a number 
of Serialization Builder implementation classes.  It is also likely that the 
static factory method Builder.new() might accept parameters or may choose 
different builder implementations under different conditions.
+ 
+ You could also for instance have two serialized forms, one old, one new. A 
configuration setting could dictate the use of only the old serialized form 
until your environment has been completely upgraded, then set the configuration 
to only use the new serialized forms.  Any old marhsalled objects (in serial 
form) will still be able to be deserialized, but no more in this form will be 
created, so will eventually disapear.
+ 
+ The Serializable Builder pattern is inspired by the Serializable Proxy 
pattern[1], where the proxy has been decoupled using an abstract builder.
+ 
+ [1] Joshua Bloch "Effective Java Second Edition" Item 78, Page 312. ISBN-10: 
0-321-35668-3
+ 

Reply via email to