rspec/rules/S2060/java/rule.adoc

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[]