Nice, Peter

Sent from my iPhone

On Oct 12, 2011, at 6:57 PM, Peter Firmstone <j...@zeus.net.au> wrote:

> Serialization has an undeserving bad reputation, perhaps caused by too many 
> developers just adding implements Serializable and accepting the default 
> serialized form in public API, then turning around and saying they won't 
> support backward compatible Serialization.
> 
> In the implementation discussed below all objects are using just one public 
> API class with static factory methods, to keep it simple for user developers.
> 
> I've been adding serialization to reference collections (just a bunch of 
> wrapper classes that encapsulate any collection framework interface and 
> perform the boilerplate of retrieving referents, wrapping them in references 
> and removing enqueued references from those collections, allowing the choice 
> of Weak, Soft, Strong references with identity, equals and comparable 
> semantics.
> 
> All the following package private wrapper classes share a single serialized 
> form at present:
> 
> ReferenceCollection
> ReferenceList
> ReferenceSet
> ReferenceSortedSet
> ReferenceNavigableSet
> ReferenceQueue
> ReferenceDeque
> ReferenceBlockingQueue
> ReferenceBlockingDeque
> 
> The serial form is generated using writeReplace, and it recreates the correct 
> collection using ReadResolve.
> 
> Now because each wrapper class is only publicly visible to the client as a 
> java collection framework (JCF) interface, the serialized form (also called a 
> serialization proxy), rebuilds it using the standard public api factory class 
> during de-serialization, based on the JCF interface it implemented.  So the 
> remote end is free to use another implementation.
> 
> Now there's a readResolve bug worth mentioning here, with regard to circular 
> references.  writeReplace replaces all original object instances with your 
> serialized form object, but readResolve doesn't replace circular referenced 
> objects during de serialization.  So if you're utilising readResolve to 
> replace your serialized form, you'll end up with a mix of the serialized form 
> object and your freshly constructed implementation object.  You'll get 
> ClassCastExceptions etc...
> 
> Bob Lee, that's Crazy Bob from JSR330 and Google Guice, came up with the idea 
> of having the serialization proxy and original objects share the same 
> interface, then having all methods redirected to the newly built object upon 
> de-serialization.
> 
> So to implement that, I've got an inheritance hierarchy for the serialization 
> proxy, to separate each function:
> 
> SerializationOfReferenceCollection
>                |
> ReadResolveFixCollectionCircularReferences
>                |
> ReferenceCollectionRefreshAfterSerialization
>                |
> ReferenceCollectionSerialData
> 
> Now right about now, you're probably saying 4 classes in an inheritance 
> hierarchy is a bit heavy for serialization?
> 
> Well no, not when you consider: they serialize 9 classes, and of all those 
> classes, only one, ReferenceCollection has to implement a final writeReplace 
> method, while all have to implement a readObject method that throws an 
> exception to prevent direct de-serialization.
> 
> So all the 9 classes are freed from the implementation of Serialization, it's 
> now the responsibility of the 4 classes in the serialization proxy 
> (Serialization builder pattern) inheritance hierarchy.
> 
> Function of each class in the inheritance hierarchy:
> 
> SerializationOfReferenceCollection is an abstract class with a static factory 
> method.
> 
> ReadResolveFixCollectionCircularReferences implements all the JCF collection 
> based interfaces and redirects their calls to the ReferenceCollection 
> implementation built during de-serialization.
> 
> ReferenceCollectionRefreshAfterSerialization, updates all the References 
> contained by the collection so they belong to the same garbage collection 
> ReferenceQueue and creates new References for all referents.
> 
> ReferenceCollectionSerialData, contains the fields transferred during 
> serialization and implements abstract methods for the super classes to "get" 
> these fields.
> 
> Now the interesting part is, I'm considering having three different 
> serialized form's, each with a different purpose, the client can choose from:
> 
> 1. A Non serialization class, that prevents serialization, where a developer 
> want's to prevent access to serialized state.
> 
> 2. The default serial data.
> 
> 3. Defensive copying of serial data, to prevent stolen references to internal 
> state during de-serialization.
> 
> The choice between the three serial states can be left until runtime,
> the recipient of these objects when serialized doesn't have a choice which 
> serial form is used, only the creator of the original object does.
> 
> Items 1 and 3 would only be used in a local sense, where a client program 
> might try to use serialization to gain access to internal implementation 
> state.
> 
> Item 2 would be used in a genuine distributed environment, over a secure 
> connection, where there is no point using defensive copy's.
> 
> I've only implemented Item 2 of course, I decided that while it is possible 
> to do 1 and 3 as well to demonstrate just how flexible serialization can be, 
> it wasn't warranted based on that alone.  It will be possible to do this at 
> some point in future, or to change the serial form in a non compatible 
> manner, by adding a new serial form class, while retaining the original, so 
> that both the old and new serial forms can be de-serialized.
> 
> When you apply Object design principals of responsibility, even serialization 
> can be flexible.
> 
> Serialized Form lock in, is the same as inappropriate use of public fields or 
> other poor programming practices.  Note that there are times where standard 
> rules don't apply like the use of public fields in Entry's, which is totally 
> appropriate, just as accepting the standard serial form in package private 
> classes is appropriate too.
> 
> Cheers,
> 
> Peter.
> 

Reply via email to