CONTENTS | PREV | NEXT


4.6 Stream Unique Identifiers

Each versioned class must identify the original class version for which it is capable of writing streams and from which it can read. For example, a versioned class must declare:

    private static final long serialVersionUID = 3487495895819393L;
The stream-unique identifier is a 64-bit hash of the class name, interface class names, methoit is strongly recommended thatds, and fields. The value must be declared in all versions of a class except the first. It may be declared in the original class but is not required. The value is fixed for all compatible classes. If the SUID is not declared for a class, the value defaults to the hash for that class. Serializable classes do not need to anticipate versioning; however, Externalizable classes do.


Note - It is strongly recommended that serializable classes that are inner classes or which contain inner classes declare the serialVersionUID data member. This is because different implementations of compilers could use different names for synthetic members that are generated for the implementation of inner classes, and these names are used in the current computation of SUIDs.
The initial version of an Externalizable class must output a stream data format that is extensible in the future. The initial version of the method readExternal has to be able to read the output format of all future versions of the method writeExternal.

The serialVersionUID is computed using the signature of a stream of bytes that reflect the class definition. The National Institute of Standards and Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a signature for the stream. The first two 32-bit quantities are used to form a 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data types to a sequence of bytes. The values input to the stream are defined by the Java Virtual Machine (VM) specification for classes.

The sequence of items in the stream is as follows:

  1. The class name written using UTF encoding.
  2. The class modifiers written as a 32-bit integer.
  3. The name of each interface sorted by name written using UTF encoding.
  4. For each field of the class sorted by field name (except private static and private transient fields):
    1. The name of the field in UTF encoding.
    2. The modifiers of the field written as a 32-bit integer.
    3. The descriptor of the field in UTF encoding
  5. If a class initializer exists, write out the following:
    1. The name of the method, <clinit>, in UTF encoding.
    2. The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer.
    3. The descriptor of the method, ()V, in UTF encoding.
  6. For each non-private constructor sorted by method name and signature:
    1. The name of the method, <init>, in UTF encoding.
    2. The modifiers of the method written as a 32-bit integer.
    3. The descriptor of the method in UTF encoding.
  7. For each non-private method sorted by method name and signature:
    1. The name of the method in UTF encoding.
    2. The modifiers of the method written as a 32-bit integer.
    3. The descriptor of the method in UTF encoding.
  8. The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and produces five 32-bit values sha[0..4].
  9. The hash value is assembled from the first and second 32-bit values of the SHA-1 message digest. If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named sha, the hash value would be computed as follows: long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF) << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) << 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) << 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) << 56;


CONTENTS | PREV | NEXT