Why is this an issue?

A class that implements java.io.Externalizable is a class that provides a way to customize the serialization and deserialization, allowing greater control over how the object’s state is written or read.

The first step of the deserialization process is to call the class' no-argument constructor before the readExternal(ObjectInput in) method.

An implicit default no-argument constructor exists on a class when no constructor is explicitly defined within the class. But this implicit constructor does not exist when any constructor is explicitly defined, and in this case, we should always ensure that one of the constructors has no-argument.

It is an issue if the implicit or explicit no-argument constructor is missing or not public, because the deserialization will fail and throw an InvalidClassException: no valid constructor..

How to fix it

This issue can be fixed by:

Code examples

Noncompliant code example

public class Tomato implements Externalizable {

  public Color color;

  // Noncompliant; because of this constructor there is no implicit no-argument constructor,
  // deserialization will fail
  public Tomato(Color color) {
    this.color = color;
  }

  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeUTF(color.name());
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException {
    color = Color.valueOf(in.readUTF());
  }
}

Compliant solution

public class Tomato implements Externalizable {

  public Color color;

  // Compliant; deserialization will invoke this public no-argument constructor
  public Tomato() {
    this.color = Color.UNKNOWN;
  }

  public Tomato(Color color) {
    this.color = color;
  }

  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeUTF(color.name());
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException {
    color = Color.valueOf(in.readUTF());
  }
}

Resources

Documentation