Skip to main content

Avoid Ignoring Members During Record Serialization

High
reliabilitydata integrity

What is it?

This practice is triggered when record classes incorrectly include members such as writeObject, readObject, readObjectNoData, writeExternal, readExternal, and serialPersistentFields, which are ignored during serialization/deserialization.

Why apply it?

In Java records, standard serialization methods and fields cannot be customized, leading to ignored logic if included. This can cause unexpected behaviors and security risks, as the ignored members go unnoticed, leading to incomplete or incorrect serialization processes.

How to fix it?

Avoid adding these ignored members to record classes. Use writeReplace and readResolve methods if customization on the object stream is needed during serialization/deserialization.

Examples

Example 1:

Negative

This negative example incorrectly includes ignored members like writeObject and serialPersistentFields in a record class.

import java.io.*;

record NonCompliantRecord(String data) implements Serializable {
@Serial
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0]; // Noncompliant

@Serial
private void writeObject(ObjectOutputStream out) throws IOException { // Noncompliant
out.defaultWriteObject();
}

@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { // Noncompliant
in.defaultReadObject();
}
}

Example 2:

Positive

This positive example demonstrates a compliant record class without any ignored members.

import java.io.Serializable;

record CompliantRecord(String data) implements Serializable {
private Object writeReplace() throws java.io.ObjectStreamException {
return this;
}

private Object readResolve() throws java.io.ObjectStreamException {
return this;
}
}

Negative

This negative example shows a noncompliant record class, mistakenly implementing the writeExternal method.

import java.io.*;

record NonCompliantExternalRecord(int identifier) implements Externalizable {
@Override
public void writeExternal(ObjectOutput out) throws IOException { // Noncompliant
out.writeInt(identifier);
}

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // Noncompliant
this.identifier = in.readInt();
}
}

Example 3:

Positive

This positive example demonstrates another compliant record without implementing any customization for serialization.

import java.io.Serializable;

record AnotherCompliantRecord(int identifier, String note) implements Serializable {
private Object writeReplace() throws java.io.ObjectStreamException {
return this;
}

private Object readResolve() throws java.io.ObjectStreamException {
return this;
}
}