Support has been added to serialization to handle enumerated
types, which are new in version 5.0. The rules for serializing an
enum instance differ from those for serializing an "ordinary"
serializable object: the serialized form of an enum instance
consists only of its enum constant name, along with information
identifying its base enum type. Deserialization behavior differs as
well--the class information is used to find the appropriate enum
class, and the Enum.valueOf method is called with that
class and the received constant name in order to obtain the enum
constant to return.

In previous releases starting with version 1.4.0, a
ClassNotFoundException thrown by the
ObjectInputStream.readClassDescriptor method would be
reflected to the top-level caller of
ObjectInputStream.readObject as a
StreamCorruptedException with an empty cause. It is
now reflected to the top-level caller as an
InvalidClassException with the original
ClassNotFoundException as the cause.

Bug fix: thread waiting on a
java.io.ObjectStreamClass$EntryFuture for notification from [sic]
(since 5.0)

In previous releases starting with version 1.4.0, the
ObjectStreamClass.lookup method could deadlock if
called from within the static initializer of the class represented
by the method's Class argument. Deadlock should no
longer occur in this case.

Bug fix: no spec for serialVersionUID (since 5.0)

The javadoc for the Serializable interface has
been expanded to more completely specify the role and usage of
serialVersionUIDs, and to emphasize the need to
specify explicit serialVersionUIDs for serializable
classes.

Support for deserialization of unshared objects (since
1.4)

Serialization now provides extra support for deserialization of
objects which are known to be unshared in the data-serialization
stream. The new support is provided by the following API additions
in package java.io:

These APIs can be used to more efficiently read contained array
objects in a secure fashion; for more information, see section A.6
of the Java Object Serialization Specification, "Guarding
Unshared Deserialized Objects".

These changes will not affect the great majority of
applications. However, it will affect any
ObjectInputStream/ObjectOutputStream subclasses which override the
putFields or readFields methods without also
overriding the rest of the serialization infrastructure.

Support for class-defined readObjectNoData method (since
1.4)

In addition to supporting class-defined writeObject()
and readObject() methods, serialization now includes
support for class-defined readObjectNoData() methods. Each
class-defined readObjectNoData() method is required to
have the following signature:

private void readObjectNoData() throws ObjectStreamException;

The readObjectNoData() method is analogous to the
class-defined readObject() method, except that (if
defined) it is called in cases where the class descriptor for a
superclass of the object being deserialized (and hence the object
data described by that class descriptor) is not present in the
serialization stream. More formally: If object O of class C is
being deserialized, and S is a superclass of C in the VM which is
deserializing O, then S.readObjectNoData() is invoked by
ObjectInputStream during the deserialization of O if and only if
the following conditions are true:

S implements java.io.Serializable (directly or
indirectly).

S defines an readObjectNoData() method with the
signature listed above.

The serialization stream containing O does not include a class
descriptor for S among its list of superclass descriptors for
C.

Note that readObjectNoData() is never invoked in cases
where a class-defined readObject() method could be called,
though serializable class implementors can call
readObjectNoData() from within readObject() as a
means of consolidating initialization code.

See the class description in the API specification of ObjectInputStream
for more information.

In previous releases, bug 4171142
caused attempts to deserialize Class objects of primitive types to
fail with a ClassNotFoundException. The problem was that
ObjectInputStream.resolveClass() did not work for
ObjectStreamClass descriptors for primitive types. This bug is
fixed in J2SE 1.4.0.

In previous releases, ObjectInputStream.resolveProxyClass would not always
select the proper class loader to define the proxy class in if one
or more of the proxy interfaces were non-public. In this release,
if ObjectInputStream.resolveProxyClass detects a
non-public interface, it attempts to define the implementing proxy
class in the same class loader as the interface (barring conflicts,
in which case an exception is thrown), which is necessary in order
for the proxy to implement the interface.

In previous releases, bug 4387368
caused NullPointerExceptions to be thrown when serializing objects
which used default serialization but also declared
serialPersistentField entries which did not map to actual class
fields. Serialization will now throw InvalidClassExceptions in such
cases (since it is never necessary to define such "unbacked"
serialPersistentFields when using default serialization).

In previous releases, ClassNotFoundExceptions triggered by
"skipped" objects--objects associated with fields not present in
the classes loaded by the deserializing party--would cause
deserialization of the entire object graph to fail, even though the
skipped values would not be included in the graph. This release of
serialization addresses this problem by ignoring
ClassNotFoundExceptions associated with such skipped objects, thus
eliminating a class of unnecessary deserialization errors. Other
miscellaneous changes have also been made to improve the overall
robustness of serialization with regards to ClassNotFoundExceptions
encountered during deserialization.

Strings longer than 64K can now be serialized (since
1.3)

Prior to 1.3, an attempt to serialize a string longer than 64K
would result in a java.io.UTFDataFormatException being
thrown. In 1.3, the serialization protocol has been enhanced to
allow strings longer than 64K to be serialized. Note that if a 1.2
(or earlier) JVM attempts to read a long string written from a
1.3-compatible JVM, the 1.2 (or earlier) JVM will receive a
java.io.StreamCorruptedException.

Serialization performance enhancements (since 1.3)

Several changes have been made to serialization to improve
overall performance:

Code for reading and writing primitive data arrays has been
streamlined. Float and double array reads/writes have been
reimplemented to minimize the number of calls to native
methods.

Internal buffering has been improved.

Reflective operations for getting/setting primitive field
values have been batched to minimize the number of separate native
method calls.

Improved exception reporting (since 1.3)

If a class cannot be found during the class resolution process
of deserialization, the original
java.lang.ClassNotFoundException is thrown instead of
a generic one so that more information about the failure is
available. Also, deserialization exception reporting now includes
maintaining the name of the original class that could not be found
instead of reporting a higher-level class that was being
deserialized. For example, if (in an RMI call) the stub class
can be found but the remote interface class cannot, the
serialization mechanism will now report correctly that the
interface class was the class that could not be found instead of
erroneously reporting that the stub class could not be found.

The writeClassDescriptor and
readClassDescriptor methods have been added to provide
a means of customizing the serialized representation of
java.io.ObjectStreamClass class descriptors.
writeClassDescriptor is called when an instance of
java.io.ObjectStreamClass needs to be serialized, and
is responsible for writing the ObjectStreamClass to
the serialization stream. Conversely,
readClassDescriptor is called when the
ObjectInputStream expects an
ObjectStreamClass instance as the next item in the
serialization stream. By overriding these methods, subclasses of
ObjectOutputStream and ObjectInputStream
can transmit class descriptors in an application-specific format.
For more information, refer to sections 2.1 and 3.1 of the Java
Object Serialization Specification.

These methods are similar in purpose to
ObjectOutputStream.annotateClass and
ObjectInputStream.resolveClass, except that they apply
to dynamic proxy classes (see
java.lang.reflect.Proxy), as opposed to non-proxy
classes. Subclasses of ObjectOutputStream may override
annotateProxyClass to store custom data in the stream
along with descriptors for dynamic proxy classes.
ObjectInputStream subclasses may then override
resolveProxyClass to make use of the custom data in
selecting a local class to associate with the given proxy class
descriptor. For details, see section 4 of the Java Object
Serialization Specification.

The javadoc tags @serial,
@serialField, and @serialData have been
added to provide a way to document the serialized form of a class.
Javadoc generates a serialization specification based on the
contents of these tags. For details, refer to section 1.6 of the
Java Object Serialization Specification.

Protocol versioning (since 1.2)

Prior to 1.2, object serialization used a protocol that did not
support skipping over objects implementing the
java.io.Externalizable interface if the classes for
those objects were not available. In 1.2, a new protocol version
was added which addressed this deficiency. For backwards
compatibility, ObjectOutputStream and
ObjectInputStream can read and write serialization
streams written in either protocol; the protocol version used can
be selected by calling the
ObjectOutputStream.useProtocolVersion method. For
details and a discussion of compatibility issues, see section 6.3
of the Java Object Serialization Specification.

Class-defined writeReplace and
readResolve methods (since 1.2)

Since 1.2, classes can define writeReplace and
readResolve methods which allow instances of the given
classes to nominate replacements for themselves during
serialization and deserialization. The required signatures of these
methods, along with further details, are described in sections 2.5
and 3.6 of the Java Object Serialization Specification.

Since 1.2, subclasses of ObjectOutputStream and
ObjectInputStream can implement a custom serialization
protocol by overriding the writeObjectOverride and
readObjectOverride methods. Note that these methods
will only be called if the
ObjectOutputStream/ObjectInputStream subclasses
possess the permission
java.io.SerializablePermission("enableSubclassImplementation"),
and call the no-argument constructors of
ObjectOutputStream/ObjectInputStream. See sections 2.1
and 3.1 of the Java Object Serialization Specification for
more information.

Security permission checks (since 1.2)

Subclasses of ObjectOutputStream and
ObjectInputStream may override inherited methods to
obtain "hooks" into certain aspects of the serialization process.
Since 1.2, object serialization uses the 1.2 security model to
verify that subclasses possess adequate permissions to override
certain hooks. The permissions
java.io.SerializablePermission("enableSubclassImplementation")
and
java.io.SerializablePermission("enableSubstitution")
govern whether or not the methods
ObjectOutputStream.writeObjectOverride,
ObjectOutputStream.replaceObject,
ObjectInputStream.readObjectOverride, and
ObjectInputStream.resolveObject will be called during
the course of serialization. See sections 2.1 and 3.1 of the
Java Object Serialization Specifications for more
information.

Defining serializable fields for a class (since
1.2)

By default, the values of all non-static and non-transient
fields of a serializable class are written when an instance of that
class is serialized. In 1.2, a new mechanism was introduced to
allow classes finer control of this process. By declaring a special
field serialPersistentFields, serializable classes can
dictate which fields will be written when instances of the class
(or subclasses) are serialized. This feature also enables classes
to "define" serializable fields which do not correspond directly to
actual fields in the class. Used in conjunction with the
serializable fields API (described below), this capability allows
fields to be added or removed from a class without altering the
serialized representation of the class. See sections 1.5 and 1.7 of
the Java Object Serialization Specification for
details.

Serializable fields API (since 1.2)

Introduced in 1.2, the serializable fields API allows
class-defined writeObject/readObject
methods to explicitly set and retrieve serializable field values by
name and type. This API is particularly useful for classes that
need to maintain backwards compatibility with older class versions;
in some cases, the older version of the class may have defined a
set of serializable fields that cannot be mapped directly to the
fields of the current class. In this case, newer versions of the
class can define custom writeObject and
readObject methods that convert the internal state of
a given instance of the (new) class into the "old" serialized form,
and vice versa. For more information, see section 1.7 of the
Java Object Serialization Specification.

*As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.