Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Once an object of a particular class has been serialized, future refactoring of the class's code often becomes problematic. Specifically, existing serialized forms (encoded representations) become part of the object's published API and must be supported for an indefinite period. This can be troublesome from a security perspective; not only does it promote dead code, it also forces the provider to maintain a compatible code base for the life lifetime of their products.

Classes that implement Serializable and do not override without overriding its functionality are said to be using the default serialized form. In the event of future changes to the class changes, byte streams produced by users of old versions of the class will be become incompatible with the new implementation. Programs must maintain serialization compatibility during class evolution. An acceptable approach is the use of a custom serialized form, which relieves the implementer of the necessity to maintain the original serialized form and the corresponding version of the class in addition to the newly evolved version.

...

This noncompliant code example implements a GameWeapon class with a serializable field called noOfWeapons, numOfWeapons and uses the default serialization form. Any changes to the internal representation of the class can break the existing serialized form.

Code Block
bgColor#FFcccc
class GameWeapon implements Serializable {
  int noOfWeaponsnumOfWeapons = 10;
	    
  public String toString() {
    return String.valueOf(noOfWeaponsnumOfWeapons);
  }
}

Because this class does not provide a serialVersionUID, the Java Virtual Machine (JVM) assigns it one using implementation-defined methods. If the class definition changes, the serialVersionUID is also likely to change. Consequently, and the JVM will refuse to associate the serialized form of an object with the class definition if when the version IDs are different.

...

In this solution, the class has an explicit serialVersionUID which that contains a number unique to this version of the class. The JVM will make a good-faith effort to deserialize any serialized object with the same class name and version ID.

Code Block
bgColor#ccccff
class GameWeapon implements Serializable {
  private static final long serialVersionUID = 24L;

  int noOfWeaponsnumOfWeapons = 10;
	    
  public String toString() {
    return String.valueOf(noOfWeaponsnumOfWeapons);
  }
}

Compliant Solution (serialPersistentFields)

Ideally, implement Serializable only when the class is not expected to evolve frequentlyfor stable classes. One way to maintain the original serialized form and at the same time allow the class to evolve is to use custom serialization with the help of serialPersistentFields. The static and transient fields allow one to specify what qualifiers specify which fields should not be serialized, whereas the serialPersistentFields field specifies what which fields should be serialized. It also relieves the class from defining the serializable field within the class implementation, decoupling the current implementation from the overall logic. New fields can easily be added without breaking compatibility across releases.

Code Block
bgColor#ccccff
class WeaponStore implements Serializable {
  int noOfWeaponsnumOfWeapons = 10; // Total number of weapons	
}

public class GameWeapon implements Serializable {
  WeaponStore ws = new WeaponStore();
  private static final ObjectStreamField[] serialPersistentFields
      = {new ObjectStreamField("ws", WeaponStore.class)};

  private void readObject(ObjectInputStream ois) throws IOException {
    try {
      ObjectInputStream.GetField gf = ois.readFields();
      this.ws = (WeaponStore) gf.get("ws", ws);
    } catch (ClassNotFoundException e) { /* Forward to handler */ }
  }
	 
  private void writeObject(ObjectOutputStream oos) throws IOException {
    ObjectOutputStream.PutField pf = oos.putFields();
    pf.put("ws", ws);
    oos.writeFields();
  }
	 
  public String toString() {
    return String.valueOf(ws);
  }
}

...

Related Guidelines

MITRE CWE

CWE-589 ". Call to Nonnon-ubiquitous API "

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="6b22da03e3f6391c-8fc9b166-453e4282-bef68e3d-e279a10a9ead400907e778be"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

 

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="9d7426d1c6c05e73-e220034f-429847f0-a23eb929-faac580408246cd873aaa27b"><ac:plain-text-body><![CDATA[

[[Bloch 2008

AA. Bibliography#Bloch 08]]

Item 74: ", Implement serialization judiciously "

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="3c63a35e506b2096-a9278522-487d4017-a0c688df-dbf730ca785aae24315cae51"><ac:plain-text-body><![CDATA[

[[Harold 2006

AA. Bibliography#Harold 06]]

13.7.5. , serialPersistentFields

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="e8c93276b6c7a770-f8f7f07b-46de4a56-b62a901a-8b00b1898a3c489d23e9af76"><ac:plain-text-body><![CDATA[

[[Sun 2006

AA. Bibliography#Sun 06]]

" Serialization specification"Specification, " 1.5, Defining Serializable Fields for a Class" , and " 1.7, Accessing Serializable Fields of a Class "

]]></ac:plain-text-body></ac:structured-macro>

...