Documentation Contents

# Object Serialization Enhancements

The following topics are covered:

- Enhancements in Java SE 6
- Enhancements in Java SE 5.0
- Enhancements in Java SE 1.4
- Enhancements in Java SE 1.3
- Enhancements in Java SE 1.2

## Enhancements in Java SE 6

`java.io.ObjectStreamClass.lookupAny`
  In previous releases, it was difficult to programmatically obtain an `ObjectStreamClass` instance for a non-serializable `Class`, although doing so can be desirable when customizing the stream format for class descriptors (see 4413615 for more information). The new method `ObjectStreamClass.lookupAny` can now be used for this purpose.
Bug fix: delayed garbage collection
  In previous releases, bug 6232010 could cause serializable classes and subclasses of `ObjectOutputStream` and `ObjectInputStream` to be strongly referenced long after their use in a serialization operation, thus possibly delaying garbage collection of their defining class loaders indefinitely. Internal caches in the serialization implementation have been restructured to fix this bug.

## Enhancements in Java SE 5.0

Support for serialization of enumerated type instances
  Support has been added to serialization to handle enumerated types, which are new in this release. 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
  In previous releases starting with 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]
  In previous releases starting with 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
  The javadoc for the `Serializable` interface has been expanded to more completely specify the role and usage of `serialVersionUID`s, and to emphasize the need to specify explicit `serialVersionUID`s for serializable classes.

## Enhancements in Java SE 1.4

Support for deserialization of unshared objects
  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`:
  - `ObjectInputStream.readUnshared()`
  - `ObjectOutputStream.writeUnshared(Object obj)`
  - `ObjectStreamField(String name, Class type, boolean unshared)`

  These APIs can be used to more efficiently read contained array objects in a secure fashion.

Security permissions now required to override putFields, readFields
  ObjectOutputStream's public one-argument constructor requires the "enableSubclassImplementation" SerializablePermission when invoked (either directly or indirectly) by a subclass which overrides `ObjectOutputStream.putFields` or `ObjectOutputStream.writeUnshared`.

  ObjectInputStream's public one-argument constructor requires the "enableSubclassImplementation" SerializablePermission when invoked (either directly or indirectly) by a subclass which overrides `ObjectInputStream.readFields` or `ObjectInputStream.readUnshared`.

  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
  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:
  1. S implements java.io.Serializable (directly or indirectly).
  2. S defines an `readObjectNoData()` method with the signature listed above.
  3. 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
  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 this release.
Bug fix: ObjectInputStream.resolveProxyClass can fail for non-public interface cases
  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
  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
  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.

## Enhancements in Java SE 1.3

Strings longer than 64K can now be serialized
  Prior to this release, an attempt to serialize a string longer than 64K would result in a `java.io.UTFDataFormatException` being thrown. In this release, 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
  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
  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.
`java.io.ObjectOutputStream.writeClassDescriptor`,
`java.io.ObjectInputStream.readClassDescriptor`
  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.
`java.io.ObjectOutputStream.annotateProxyClass`,
`java.io.ObjectInputStream.resolveProxyClass`
  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`
  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.

## Enhancements in Java SE 1.2

Protocol versioning
  Prior to this release, 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 this release, 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
  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.
`java.io.ObjectOutputStream.writeObjectOverride`, `java.io.ObjectInputStream.readObjectOverride`
  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
  Subclasses of `ObjectOutputStream` and `ObjectInputStream` may override inherited methods to obtain "hooks" into certain aspects of the serialization process. Since this release, 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
  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 this release, 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
  Introduced in this release, 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.

Copyright © 1993, 2026, Oracle and/or its affiliates. All rights reserved.
Contact Us