Friday, December 25, 2009

Section 13.12. JavaDoc










13.12. JavaDoc




Documenting the serialized form of a class is important when you need to interoperate with different implementations of the same API. For instance, the open source GNU Classpath library should be able to deserialize objects serialized by Sun's class library and vice versa, even though they share no code and indeed may have quite different private data. JavaDoc has three tags specifically to document the serialized form of a class: @serial, @serialField, and @serialData. The javadoc
application reads these tags to generate a description of the serialization format of each Serializable class.



13.12.1. @serial


An @serial tag should be attached to each nontransient instance field. The content of this tag should describe the meaning of the field and the any constraints on its values. For example, this is how you might document the x and y fields in the TwoDPoint class:



import java.io.Serializable;
public class TwoDPoint implements Serializable {
/** @serial the X-coordinate of the point;
* any double value except NaN
*/
private double x;
/** @serial the Y-coordinate of the point;
* any double value except NaN
*/
private double y;
//...



This is a major violation of data encapsulation, but then serialization pretty much always is. Of course, there's no rule that says an alternate implementation of this class has to use two double x and y fields. It could use BigDecimals or doubles expressing polar coordinates. However, for compatibility when serializing, it should be prepared to write two doubles expressing Cartesian coordinates. The serialized form ultimately becomes just another part of the class's published interface, albeit one you can ignore for most operations.




13.12.2. @serialData


A class that customizes the serialization format by implementing writeObject( ) or writeExternal( ) should annotate those methods with an @serialData tag explaining in detail the format written. For example, the writeObject( ) method in SerializableZipFile could be documented like this:



/** @serialData the name of the file is written as a String.
* No other data is written.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(zf.getName( ));
}



This example's quite simple. Of course, the more complex the custom serialization format, the longer and more complex the comment will be.




13.12.3. @serialField


Finally, if you have a serialPersistentFields array, each ObjectStreamField component of the array should be documented by @serialField tag. This tag is followed by the name of the field, the type of the field, and the description of the field. For example, this comment documents a serialPersistentFields array for the TwoDPoint:



/**
* @serialField x double the Cartesian x-coordinate; never NaN
* @serialField y double the Cartesian y-coordinate; never NaN
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("x", double.class),
new ObjectStreamField("y", double.class)
};




If you're starting to get the idea that object serialization is more complex than you thought, you're probably right. Doing object serialization properly takes forethought, care, and effort. It is not just a simple matter of declaring that a class implements Serializable and writing objects onto streams. Doing object serialization wrong can lead to brittle code that breaks every time you make small changes to what look like private parts of a class. It can lock you into a data structure you'd really rather change.


That's not to say you shouldn't use object serialization. There are many cases where it fits well, and if you have one of those cases, by all means use it. However, don't use it lightly. Make sure a class really needs to be serializable before you type "implements Serializable." In particular, do not make your classes Serializable out of habit. It's best to default to unserializable classes. After all, you can always add serialization support later if you find a need for it. It's much harder to take away a feature, even one that's causing you pain, after other developers are relying on it.















No comments: