98 lines
2.6 KiB
Plaintext
98 lines
2.6 KiB
Plaintext
== 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:
|
|
|
|
* Adding an explicit public no-argument constructor.
|
|
* Or if all constructors can be removed, remove all constructors to benefit of the default implicit no-argument constructor.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,java,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
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
|
|
|
|
[source,java,diff-id=1,diff-type=compliant]
|
|
----
|
|
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
|
|
|
|
* https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/Externalizable.html[Oracle SDK - java.io.Externalizable]
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Add a no-arg constructor to this class.
|
|
|
|
|
|
endif::env-github,rspecator-view[]
|