Support for serialization of enumerated type instances (since 5.0)
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.
Bug fix: java.io.StreamCorruptedException thrown due to
java.lang.ClassNotFoundException (since 5.0)
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".
Security permissions now required to override putFields, readFields
(since 1.4)
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:
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.
Bug fix: Deserialization fails for Class object of primitive type (since
1.4)
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.
Bug fix: ObjectInputStream.resolveProxyClass can fail for non-public
interface cases (since 1.4)
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.
Bug fix: Invalid serialPersistentFields field name causes
NullPointerException (since 1.4)
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).
Bug fix: ClassNotFoundException in skipped objects causes
serialization to fail (since 1.4)
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.
Several changes have been made to serialization to improve overall
performance:
UTF string reads/writes have been optimized to reduce unnecessary memory
allocation and synchronization/method call overhead.
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 tool tags @serial, @serialField, and
@serialData (since 1.2)
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.